Difference between revisions of "Visual Prolog 11 Upgrade Notes"
(mach & case) |
m (remove line shift) |
||
Line 30: | Line 30: | ||
<vp>regEx::</vp><b>match</b> has been retired and renamed to <vp>regEx::matchFirst</vp> | <vp>regEx::</vp><b>match</b> has been retired and renamed to <vp>regEx::matchFirst</vp> | ||
=== gdiplus === | === gdiplus === |
Latest revision as of 10:30, 8 April 2024
This document describes how to upgrade Visual Prolog 10 projects to Visual Prolog 11, for older projects you should also read the Visual Prolog 10 Upgrade Notes.
If you have problems with upgrading your projects and need additional information, you are welcome to ask questions in Visual Prolog Discussion Forum.
By default, the installation of Visual Prolog 11 will not replace any older installed versions. It is possible to work with several versions on a single computer. See also vipLaunch.
The Commercial and Personal Edition are identical; differences in capabilities are controlled by the license used to activate the computer.
Entities that are not available to Personal Edition usage are marked with the attribute [feature("Commercial Edition")].
Visual Prolog 11 is installed per user in ...\Users\<user>\AppData\Roaming\Visual Prolog\11.
Visual Prolog 11 project files are backward-compatible with Visual Prolog 10 project files.
Notice it is highly advisable to have a backup of a project before updating.
When updating a project you should open the project in the new IDE and accept to remove any non-existing PFC packages. Then build the project and accept to
- delete all bad include directives
- insert new ones and
- add new PFC packages
Superfluous Files
If you haven't removed the superfluous resource files then see Visual Prolog 10 Upgrade Notes#Superfluous_files.
match & case future keywords
match and case will be keywords in future releases of Visual Prolog and you will receive warnings if you use them.
regEx::match has been retired and renamed to regEx::matchFirst
gdiplus
If your project initializes gdiplus, e.g. like this:
clauses run() :- _ = mainForm::display(gui::getScreenWindow()), GDIpToken = gdiplus::startup(), messageLoop::run(), gdiplus::shutdown(GDIpToken).
Then simply remove the calls to gdiplus::startup and gdiplus::shutdown code:
clauses run() :- _ = mainForm::display(gui::getScreenWindow()), messageLoop::run().
The color class/interface has been retired, and superseded by the domain gdiplus_native::color. In many cases you simply have to remove the call to color::create.
This line (in the 'GDI+ Example)
DarkRed = pen::createColor(color::create(gdiplus_native::darkred), penWidth, unit),
has been changed to:
DarkRed = pen::createColor(gdiplus_native::darkred, penWidth, unit),
A little editor trick: if you use autoformatting of code (a project setting) you can just remove color::create:
DarkRed = pen::createColor((gdiplus_native::darkred), penWidth, unit),
When you save the file the superfluous parentheses will be removed automatically. Therefore you can correct an entire file simply by replacing all occurrences of color::create with nothing/blank.
Furthermore, some domains have been relocated from the gdiplus class to the gdiplus_native class. The "Fix" button in the error window should handle that problem automatically. Otherwise, the IDE command Insert -> Qualification Ctrl+Shift+S can also insert or correct the qualification.
The object predicate graphics::drawString/6 has been retired, instead you will have to choose between:
predicates drawStringIn : (font Font, brush Brush, rectF LayoutRect, string String, stringFormat StringFormat = stringFormat::null). drawStringAt : (font Font, brush Brush, pointF Origin, string String, stringFormat StringFormat = stringFormat::null).
- graphics::drawStringIn draws the string in the rectangle LayoutRect or
- graphics::drawStringAt draws the string at the point Origin
treeModel_std & treeNode_std
If you use the treeControl with the treeModel_std you will have to add code::value as argument to treeModel_std and treeNode_std. Notice that this is not necessary in clauses; only in other places (declarations, ...).
Here illustrated with code from the dragNdropDemo in the examples:
implement mainForm inherits formWindow open core, vpiDomains, treeModel_std{core::value} ... predicates onDragBegin : treeControl{treeNode_std{value}}::dragBeginResponder. ... % This code is maintained automatically, do not update it manually. 10:41:58-23.11.2011 facts treeCtl : treecontrol{treeNode_std{value}}. ...
Notice that if you have deleted the form/dialog file (as described in superfluous Files) then you can (despite the warning in the comment) edit directly in the "auto"-code.
codePageId ansi & threadAnsi
The following codePageID's have been deprecated:
constants ansi : codePage = 0 [deprecated("It is recommended not to use this codepage, but use an explicit encoding instead")]. threadAnsi : codePage = 3 [deprecated("It is recommended not to use this codepage, but use an explicit encoding instead")]. % @short Represents the systems/threads current ANSI codePage. % It is recommended not to use this codepage but use an explicit encoding instead. % @end
The problem with these system/user codepages is that they are often set to some regional codepage with 8 bit characters. Files written like must be read with the same codepage, otherwise characters may become wrong or even lost.
Some time ago (unknown when) Microsoft have introduced the possibility to use utf-8 as system/user codepage. Using utf-8 is technically the best choice, because it "unites" all regional "things" into a single codepage. However but the transition from old regional codepages to utf-8 is "difficult", because you will still need to read a file with the codepage that was used to write it.
We recommend that you "migrate" text files to utf-8 (or utf-16 if you mainly use "special" characters, like chinese). If you add a byte order mark the format becomes "visible", but in some contexts (certain Internet contexts and using foreign applications) byte order marks in utf-8 files will not be accepted.
Fallback CodePage
Several text file related predicates have been equipped with a non-optional FallbackCodePage argument. For example:
class inputStream_file : inputStream ... constructors openFileText : (string Filename, codePage FallbackCodePage, fileSystem_api::accessPermit Access = fileSystem_api::permitRead).
The predicate inputStream_file::openFileText examines the file to open searching for Byte Order Marks and obvious utf-16 format. If it is not possible to determine the codepage like that the FallbackCodePage will be used. Such predicates used to user the threadAnsi codepage, but (as described above) this can lead to problems with "old" files and new settings and files written on one computer and read on another. For this reason you must now (explicitly) decide which codepage to use if it cannot be inferred.
COM component classes
The import of COM components has been simplified for certain COM components. Instead of being defined in a separate Visual Prolog class many COM components are now created by calling a predicate.
For example, to create an XMLHTTP component you would construct object using the corresponding constructor XmlHttp = xmlhttp60::new(), now you will instead call the predicate XmlHttp = msxml_HTTP_api::newXmlhttp60().
watchDirectory
watchDirectory has been updated to use suspending predicates, and as result watchDirectory::start takes an executionContext as argument. In most cases pfc\asynchronous\executionContext_pool::defaultPool can be used.
WD = watchDirectory::start(FullDir, pfc\asynchronous\executionContext_pool::defaultPool),
Master/slave
The master/slave concept has been updated to use suspending predicates instead of explicit continuations. The article Master/slave processes and the corresponding demo example has been updated to reflect the changes.
Web Services & webSockets
The Web Services and webSockets support has been updated to use suspending predicates for asynchronous operation. The main updates necessary to make an old program working is remove all access to threadpools.
This code
clauses runServer() :- ... mkService(Session, "File service", "", requestQueue_content::new(threadpool, demoFileService::contentMapper)), ...
will look like this:
clauses runServer() :- ... mkService(Session, "File service", "", requestQueue_content::new(demoFileService::contentMapper)), ...
If necessary you can add an explicit executionContext (Ctx):
clauses runServer() :- httpServer_api::httpInitialize(httpServer_native::http_initialize_server), Session = session::new(), Ctx = pfc\asynchronous\executionContext_pool::defaultPool, try cleanup:alsoDispose(Session), % Demo file service for html, JavaScript , images, etc to the client mkService(Session, "File service", "", requestQueue_content::new(demoFileService::contentMapper, Ctx)), ...
The changes in webSocket requires more attention. You will have to remove continuations and use suspending predicates instead.
For example, the predicate onAttach_async must now be a suspending predicate:
interface webSocketService predicates onAttach_async : (httpRequest Request, webSocket WebSocket) suspending. ...
The implementation of this predicate:
clauses onAttach_async(Request, WebSocket, Continuation) :- onAttach2_async(filename::getLastDirectory(Request:path, _), WebSocket, Continuation).
should drop the Continuation argument:
clauses onAttach_async(Request, WebSocket) :- onAttach2_async(filename::getLastDirectory(Request:path, _), WebSocket).
onAttach2_async should also be declared as a suspending predicate (without a continuation argument):
predicates onAttach2_async : (string Last, webSocket WebSocket) suspending.
The interesting part is that the real functional predicates like:
class predicates echoLoop_async : (webSocket WebSocket, continuation{unit} Continuation). clauses echoLoop_async(WebSocket, Continuation) :- WebSocket:readMessage_async( Continuation:mkContinue( { (Message) :- if webSocket::close(Status, Reason) = Message then if 0 <> Status then stdio::writef("Closed:% %\n", Status, Reason) end if, Continuation:success(unit) else if webSocket::ss(U16) = Message then stdio::writef("Message:%\n", segmented_utf16::getAsString(U16)) end if, WebSocket:writeMessage_async(Message, Continuation:mkContinue( { :- echoLoop_async(WebSocket, Continuation) % })) end if })).
Should now be implemented as a suspending predicate which result in much simpler code:
class predicates echoLoop_async : (webSocket WebSocket) suspending. clauses echoLoop_async(WebSocket) :- Message = WebSocket:readMessage_async(), if webSocket::close(Status, Reason) = Message then if 0 <> Status then stdio::writef("Closed:% %\n", Status, Reason) end if else if webSocket::ss(U16) = Message then stdio::writef("Message:%\n", segmented_utf16::getAsString(U16)) end if, WebSocket:writeMessage_async(Message), echoLoop_async(WebSocket) end if.
Especially, notice that this fragment of the code:
clauses ... WebSocket:readMessage_async( Continuation:mkContinue( { (Message) :- ... })).
simply becomes an ordinary call:
clauses ... Message = WebSocket:readMessage_async(), ...