21 March 2018

Function and Sub parameters

In the new English Html help additional information is provided for Function and Sub. Since this is new information a copy of the text has a place in a blogpost.

Function parameters
The return value of a Function can be assigned to a local variable with the same name as the Function. When the return type is a numeric data type a local variable of that type is automatically added to the function’s local variables. With String, Type (UDT) and Variant a by reference variable is passed as the last argument on the stack. The string, UDT or variant becomes the variable that can be used to pass the function’s return value. Therefor, the following is equal:

Dim h$
h$ = testf(8) ' assign result to h$
testp(8, h$)  ' put result in h$
Function testf(a%) As String testf = "3" & a%
Procedure testp(a%, ByRef p$) p$ = "3" & a%

In the function testf the variable h$ is silently passed on the stack. Inside the function this by reference variable is known as testf. Assigning a new string to testf actually assigns the string to h$ directly.

When a Function is used for a Windows API callback make sure the return data type is a primary numeric type (Byte, Word, Long, Int64, Single, Double), otherwise the stack will be overwritten.

Sub parameters
To provide compatibility with VB’s Sub, which - for instance - allows to pass literal values by reference(!), GB offers a special type of calling convention for the Sub. This GB implementation for Sub differs from the usual way of passing parameters by reference. The default state for passing arguments to a Sub is an implicit by reference; by omitting the ByVal or ByRef keywords the arguments are passed by reference. However, there is a difference between the default ByRef and an explicit ByRef.

When in a Sub declaration ByRef is omitted the argument is first copied to a hidden local variable whose address is then passed by reference. The data type of the hidden local copy depends on the data type of the implicit ByRef parameter. So, a Sub parameter without explicit ByRef does not modify the variable (actual or hidden) that is passed to the Sub. This way it is possible to pass incompatible data types by reference. It also allows for passing literal values because they are first copied to a hidden local variable that is then passed by reference. For the sub these implicit by reference variables are a kind-of  ‘read-only’ since using them doesn’t influence the value that was passed to the sub.

This adds an additional feature to the GB-language. In contrast with by value parameters, that require a copy of an argument on the stack, implicit ByRef makes a copy first and then puts the address of that copy on the stack. To prevent the creation and passing of hidden local copies, ByRef must be included explicitly in the Sub declaration. Doing so ensures that only actual variables of the correct type are passed to the Sub.

Example of implicit by reference:

Dim vnt
test(7)     ' 7 is assigned to a local Variant first
test(vnt)   ' vnt is copied to a local Variant first

Sub test(vnt As Variant)  ' implicit ByRef, read-only
  vnt = "new Value"       ' not returned to caller

Example of explicit  by reference calling convention:

testbyref(7)     ' syntax error: variable expected
testbyref(vnt)   ' vnt itself is passed

Sub testbyref(ByRef vnt As Variant)
  vnt = "new value"

04 March 2018

GfaWin23.Ocx Update 2.34

Another three bugs are fixed in this version. The SetPrinterByName needed maintenance because of the always growing need of memory with newer versions of Windows. The command failed with some printers that returned a lot of information in the GetPrinter() API. GFA-BASIC did not reserve enough memory and caused a buffer overrun. The EOF() function now also works with inline files, the ones that are stored in the :Files section of the program. The ListView.GetFirstVisible property now returns a ListItem.

About Version-numbering
The update gets FileVersion 2.34.1803 and still belongs to GFA-BASIC product version 2.3. The Build number now shows the year and month of the release. This is the first update with the new version structure. The DllVersion$ is 2.34 Build 1803 and indicates a release date of March 2018. A DLLVERSION structure always uses a 3 part format, major, minor and build. The VERSIONINFO resource on the other hand uses 4 part format. The GfaWin23.Ocx VERSIONINFO structure == 2.34.1803.0 and leaves the last part unused. This is the version showed in the File Properties dialog:

The ocx extension indicates a DLL with OCX-controls that are described using a type library. In contrast with the purpose of the extension, the OCX controls are not publically registered and are only available within in GFA-BASIC 32.

All OLE classes defined in the GfaWin23.ocx are private to the GFA-BASIC 32 application, each OLE class is implemented with its own command. This leaves no room for dynamically loading of other COM classes and automatic use of their interfaces (like VB). Third party COM classes can only be used when they implement a dual interface so they are accessible through a dispatch identifier. In GFA-BASIC these dual interface classes are supported through the use of CreateObject and the Object.property syntax. Unfortunately, calling an interface member (property/method) requires a two step process. First the caller must ask the server for an ID number and then use that number to actually invoke the member (property/method). Each dot operator requires this two step process and accessing dual interface members can cost quite some time when a command consists of many dots. For instance something like this: Object.List.Items(n).Text requires 6 calls to the COM-class provider. GFA-BASIC 32 provides a hidden optimization for automation objects created with CreateObject(). It caches all IDs in a hash-table the first time they are used. The next time a property/method is used it is looked up in the hash-table which is considerably faster.