Monthly Archives: August 2020

New Clarion language features

Some exciting new features in the Clarion language will be introduced in the next build for C11: Reference variables of Procedure types are supported by the compiler, and corresponding support is added to the linker and RTL.

Declaration of a Procedure reference

A reference variable of a procedural type is declared as follows:

Ref &<procedure label>

where <procedure label> is the label of a previously declared Procedure, a parameter of procedural type, or the label of a method in a CLASS or INTERFACE. If there is more than one Procedure or Class/Interface method with the label (for example, a class method is overloaded), or there is a data declaration with the same label in the current scope/context, the compiler returns an error.

A previous MAP structure must contain the corresponding Procedure type declaration to allow references to a Class or Interface method:

  MAP 
    MethodNameType  PROCEDURE (*ClassId, <other parameters>),...,TYPE       
  END

Ref   &MethodNameType

We’re also considering a possible extension in the future is to allow the <procedure label> to include the Class or Interface identifier as part of the declaration, for example:
Ref &ClassId.MethodName

2. Procedure Reference assignments

The reference assignment to a reference variable of procedural type has the same form as for any other reference assignment:

RefVar &= <source>

For reference assignments to reference variables of procedural types the right-hand side can be any one of the following:

1) NULL
2) an expression where the value can be converted to a LONG type
3) the label of a reference variable of procedural type
4) the label of a parameter of procedural type
5) the label of a Procedure declared in a MAP structure
6) the label of a Class method

For (3),(4) and (5) the profile of a Procedure, or a procedural type on the right hand side must be exactly the same as the profile of the procedural type used in the declaration of the reference variable on the left hand side:

meaning it must match the number of, the types of parameters, the return type, and the calling convention. (or both sides can have no return type)

For (6) if the method label on the right side is overloaded, the compiler tries to find the method with the most suitable profile. In this case “suitable” means that the first parameter (class type) on the right side can also be of a type which is a descendant
of the class type of the first parameter in the profile of the reference variable’s type. All other parameters, their order, return type, and the calling convention must be exactly the same.

The identifier on the right side can include:

  • the label of an instance of a class type, or the label of an interface
  • the label of a reference variable assigned to a class type
  • the label of a reference variable assigned to an interface type
  • the SELF or PARENT keywords
  • the label of a Class type

For example:

CType    CLASS,TYPE
M          PROCEDURE (LONG),LONG,PASCAL,VIRTUAL
         END

         MAP
PType     PROCEDURE (*CType, LONG),LONG,PASCAL
         END

R1       &PType
R2       &MESSAGE  ! the MESSAGE - built-in function
RC       &CType
AClass   CType

  CODE

  RC &= AClass
  R1 &= NULL
  R1 &= AClass.M
  R1 &= RC.M
  R1 &= CType.M
  R2 &= 0 + SYSTEM {PROP:MessageHook}

3. Reference equality operator

The reference equality operator for the reference variable of a procedural type has the same form as for any other reference variables:

Ref &= <right side>

If the left side of the reference equality operator is a reference variable of procedural type,
the <right side> can be of any form as the <source> described above in the “Procedure Reference Assignments” section.

There is one exception for this: if the <right side> is a label of a Class/Interface method, and this label is overloaded, the compiler reports an error; “Error: Ambiguous reference type“, rather than trying to choose the intended matching variation of the method.

4. Usage

A Reference variable of a procedural type can be used in any context where procedures/functions with the same profiles are valid:

  • call statements
  • a parameter of a procedural type
  • the Sort function parameter in QUEUE statements ADD, GET, PUT and SORT
  • as a parameter of the ADDRESS function
  • as a parameter of the BIND statement

Probably the most typical variations of usage for procedural type references are:

  • Calling DLL functions from addresses returned by the Windows API’s GetProcAddress function
  • SYSTEM hooks properties are no longer write-only in the upcoming RTL release. The result of getting these properties are RTL internal functions implementing corresponding statements:
    MESSAGE, COLORDIALOG, FONTDIALOG and other standard dialogs,
    OPEN for Windows and Reports, CLOSE for Windows and Reports, changing SYSTEM properties, etc.

    This means your program can retrieve the RTL’s hook function and replace it with your own function, which calls the original RTL code internally
  • Simulation of virtual functions in cases where the actual function can be changed at run time.

5. Some General info

  • Reference variables of procedural type can be declared as a field in GROUP/QUEUE/CLASS declarations
  • The DIM attribute is currently invalid for declarations of reference variables, and that same rule applies for reference variables of procedural types.
  • The ADDRESS function supports Class type labels in the identifiers of methods passed as parameters, for example, using the declarations from the example above the following expression:

    ADDRESS (CType.M)

    is valid in the upcoming release.

The new language enhancements can be likened to a pointer-to-method, and reference-to-method in C++. But in C++ a special syntax is used to allow the compiler and linker to handle these language constructs properly. No special syntax is required in Clarion.


TYPEd Class Methods

Another powerful language enhancement available in the upcoming release is support for TYPEd Class methods. I’ll be making a separate post on typed Class methods with an example of usage.