4D v13.4

Syntax Details

Home

 
4D v13.4
Syntax Details

Syntax Details  


 

 

The compiler expects that the usual syntactic rules for 4D commands are followed. It does not require any special modifications for databases that will be compiled.

This section nevertheless provides certain reminders and specific details:

  • Some commands that affect a variable's data type may lead, if you are not careful, to data type conflicts.
  • Since certain commands use more than one kind of syntax or parameters, it is to your advantage to know which is the most appropriate one to select.

Strings  

For commands operating on strings, only the Character code function requires special attention. In interpreted mode, you can pass either a non-empty string or an empty string to this function.
In compiled mode, you cannot pass an empty string.
If you pass an empty string, and if the argument passed to Character code is a variable, the compiler will not be able to detect an error in compilation.

SEND VARIABLE(variable)
RECEIVE VARIABLE(variable)

These two commands are used for writing and receiving variables sent to disk. Variables are passed as parameters to these commands.

The parameter you pass must always be of the same data type. Suppose you want to send a list of variables to a file. To eliminate the risk of changing data types inadvertently, we recommend that you specify the data type of the variables being sent at the head of the list. This way, when you receive these variables, you will always begin by getting an indicator. Then, when you call RECEIVE VARIABLE, the transfer is managed by a Case of statement.

Example:
 SET CHANNEL(12;"File")
 If(OK=1)
    $Type:=Type([Client]Total_TO)
    SEND VARIABLE($Type)
    For($i;1;Records in selection)
       $Send_TO:=[Client]Total_TO
       SEND VARIABLE($Send_TO)
    End for
 End if
 SET CHANNEL(11)
 SET CHANNEL(13;"MyFile")
 If(OK=1)
    RECEIVE VARIABLE($Type)
    Case of
       :($Type=Is String Var)
          RECEIVE VARIABLE($String)
  `Processing variable received
       :($Type=Is Real)
          RECEIVE VARIABLE($Real)
  `Processing variable received
       :($Type=Is Text)
          RECEIVE VARIABLE($Text)
  `Processing variable received
    End case
 End if
 SET CHANNEL(11)

Field (field pointer) or (table number;field number)
Table(table pointer)
or (table number) or (field pointer)

These two commands return results of different data types, according to the parameters passed to them:

  • If you pass a pointer to the Table function, the result returned is a number.
  • If you pass a number to the Table function, the result returned is a pointer.

Keep in mind that the document references returned by the Open document, Append document and Create document functions are of the data type Time.

Math  

Mod (value;divider)

The expression “25 modulo 3” can be written in two different ways in 4D:

 Variable:=Mod(25;3)

or

 Variable:=25%3

The compiler sees a difference between the two: Mod applies to all numerics, while the operator % applies only to Integers and Long Integers. If the operand of the % operator exceeds the range of the Long Integer data type, the returned result is likely to be wrong.

IDLE
ON EVENT CALL (Method{; ProcessName})
ABORT

The IDLE command has been added to 4D language to manage exceptions. This command should be used whenever you use the ON EVENT CALL command.

This command could be defined as an event management directive.
Only the kernel of 4D is able to detect a system event (mouse click, keyboard activity, and so forth). In most cases, kernel calls are initiated by the compiled code itself, in a way that is transparent to the user.

On the other hand, when 4D is waiting passively for an event––for example, in a waiting loop––it is clear that there will be no call.

  `MouseClick Method
 If(MouseDown=1)
    <>vTest:=True
    ALERT("Somebody clicked the mouse")
 End if
 
  `Wait Method
 <>vTest:=False
 ON EVENT CALL("MouseClick")
 While(<>vTest=False)
  `Event's waiting loop
 End while
 ON EVENT CALL("")

In this case, you would add the IDLE command in the following manner:

  `Wait Method
 <>vTest:=False
 ON EVENT CALL("MouseClick")
 While(<>vTest=False)
    IDLE
  `Kernel call to sense an event
 End while
 ON EVENT CALL("")
ABORT  

Use this command only in error-handling project methods. It works exactly as it does in 4D, except in a method that has been called by one of the following commands: EXECUTE FORMULA, APPLY TO SELECTION or APPLY TO SUBSELECTION. Try to avoid this situation.

Arrays  

Seven 4D commands are used by the compiler to determine the data type of an array. They are:

COPY ARRAY(source;destination)
SELECTION TO ARRAY(field;array)
ARRAY TO SELECTION(array;field)
SELECTION RANGE TO ARRAY(start;end;field;array)
LIST TO ARRAY(list;array{; itemRefs})
ARRAY TO LIST(array;list{; itemRefs})
DISTINCT VALUES(field;array)

The COPY ARRAY command accepts two array type parameters. If one of the array parameters is not declared elsewhere, the compiler determines the data type of the undeclared array from the data type of the declared one.
This deduction is performed in the two following cases:

  • The array typed is the first parameter. The compiler assigns the data type of the first array to the second array.
  • The declared array is the second parameter. Here, the compiler assigns the data type of the second array to the first array.

Since the compiler is strict about data types, COPY ARRAY can be performed only from an array of a certain data type to an array of the same type.
Consequently, if you want to copy an array of elements whose data types are similar, i.e., Integers, Long Integers and Reals, or Texts and Strings, or Strings with different lengths, you have to copy the elements one by one.

Suppose you want to copy elements from an Integer array to a Real array. You can proceed as follows:

 $Size:=Size of array(ArrInt)
 ARRAY REAL(ArrReal;$Size)
  `Set same size for Real array as the Integer array
 For($i;1;$Size)
    ArrReal{$i}:=ArrInt{$i}
  `Copy each of the elements
 End for

Remember that you cannot change the number of dimensions of an array during the process. If you copy a one-dimensional array into a two-dimensional array, the compiler generates an error message.

As with 4D in interpreted mode, these four commands do not require the declaration of arrays. The undeclared array will be assigned the data type of the field specified in the command.

If you write:

 SELECTION TO ARRAY([MyTable]IntField;MyArray)

the data type of MyArray would be an Integer array having one dimension (assuming that IntField is an integer field).

If the array has been declared, make sure that the field is of the same data type. Although Integer, Longint and Real are similar types, they are not equivalent.

On the other hand, in the case of Text and String data types, you have a little more latitude. By default, if an array was not previously declared and you apply a command that includes a String type field as a parameter, the default data type assigned to the array is Text. If the array was previously declared as String or Text, these commands will follow your directives.

The same is true for Text type fields––your directives have priority.

Remember that the  SELECTION TO ARRAY, SELECTION RANGE TO ARRAY, ARRAY TO SELECTION and DISTINCT VALUES commands can only be used with a one-dimensional array.

The SELECTION TO ARRAY command also has a second syntax:
SELECTION TO ARRAY(table;array).

In this case, the MyArray variable will be an array of Longints. The SELECTION RANGE TO ARRAY command works in the same way.

The LIST TO ARRAY and ARRAY TO LIST commands only concern two types of arrays:

  • one-dimensional String arrays, and
  • one-dimensional Text arrays.

The compiler cannot detect a data type conflict if you use a dereferenced pointer as a parameter to an array-declaration command. If you write:

 SELECTION TO ARRAY([Table]Field;Pointer->)

where Pointer-> stands for an array, the compiler cannot check whether the field type and array type are identical. It is up to you to prevent such conflicts; you should type the array referred to by the pointer.

The compiler issues a warning whenever it encounters an array declaration statement in which one of the parameters is a pointer. These messages can be helpful in detecting this type of conflict.

If your database uses local arrays (arrays recognized only in the method in which they were created), it is necessary to declare them explicitly in 4D before using them.

To declare a local array, use one of the array commands such as ARRAY REAL, ARRAY INTEGER, etc.

For example, if a method creates a local Integer array with 10 elements, you need to declare the array before using it. Use the command:

 ARRAY INTEGER($MyArray;10)

Get pointer(varName)
Type (object)
EXECUTE FORMULA(statement)
TRACE
NO TRACE

Get pointer is a function that returns a pointer to the parameter that you passed to it. Suppose you want to initialize an array of pointers. Each element in that array points to a given variable. Suppose there are twelve such variables named V1, V2, …V12. You could write:

 ARRAY POINTER(Arr;12)
 Arr{1}:=->V1
 Arr{2}:=->V2
 
 Arr{12}:=->V12

You could also write:

 ARRAY POINTER(Arr;12)
 For($i;1;12)
    Arr{$i}:=Get pointer("V"+String($i))
 End for

At the end of this operation, you get an array of pointers where each element points to a variable Vi.

These two sequences can be compiled. However, if the variables V1 to V12 are not used explicitly elsewhere in the database, the compiler cannot type them. Therefore, they must be used or declared explicitly elsewhere.
Such explicit declaration may be performed in two ways:

  • By declaring V1, V2, …V12 through a compiler directive:
 C_LONGINT(V1;V2;V3;V4;V5;V6;V7;V8;V9;V10;V11;V12)
  • By assigning these variables in a method:
 V1:=0
 V2:=0
 
 V12:=0

Since each variable in a compiled database has only one data type, this function may seem to be of no use. However, it can be useful when you work with pointers. For example, you may need to know the data type of the variable to which a pointer refers; due to the flexibility of pointers, one cannot always be sure to what object it points.

This command offers benefits in interpreted mode that are not carried over to compiled mode.

In compiled mode, a method name passed as a parameter to this command is interpreted. Therefore, you miss some of the advantages provided by the compiler, and your parameter's syntax cannot be checked.

Moreover, you cannot pass local variables as parameters to it.

EXECUTE FORMULA can be replaced by a series of statements. Two examples are given below.

Given the following sequence:

 i:=FormFunc
 EXECUTE FORMULA("FORM SET INPUT (Form"+String(i)+")")

It can be replaced by:

 i:=FormFunc
 VarForm:="Form"+String(i)
 FORM SET INPUT(VarForm)

Below is another example:

 $Num:=SelPrinter
 EXECUTE FORMULA("Print"+$Num)

Here, EXECUTE FORMULA can be replaced with Case of:

 Case of
    :($Num=1)
       Print1
    :($Num=2)
       Print2
    :($Num=3)
       Print3
 End case

The EXECUTE FORMULA command can always be replaced. Since the method to be executed is chosen from the list of the database's project methods or the 4D commands, there is a finite number of methods. Consequently, it is always possible to replace EXECUTE FORMULA with either Case of or with another command. Furthermore, your code will execute faster.

These two commands are used in the debugging process. They serve no purpose in a compiled database. However, you can keep them in your methods; they will simply be ignored by the compiler.

Undefined(variable)
SAVE VARIABLES(document;variable1{; variable2…})
LOAD VARIABLES(document;variable1{; variable2…})
CLEAR VARIABLE(variable)

Considering the typing process carried out by the compiler, a variable can never be undefined in compiled mode. In fact, all the variables have been defined by the time compilation has been completed. The Undefined function therefore always returns False, whatever parameter it is passed.

Note: To know if your application is running in compiled mode, call the Is compiled mode command.

In interpreted mode, you can check that the document exists by testing if one of the variables is undefined after performing a LOAD VARIABLES. This is no longer feasible in compiled databases, because the Undefined function always returns False.

This test can be performed in either interpreted or compiled mode by:

1. Initializing the variables that you will receive to a value that is not a legal value for any of the variables.

2. Comparing one of the received variables to the initialization value after LOAD VARIABLES.

The method can be written as follows:

 Var1:="xxxxxx"
  `"xxxxxx" is a value that cannot be returned by LOAD VARIABLES
 Var2:="xxxxxx"
 Var3:="xxxxxx"
 Var4:="xxxxxx"
 LOAD VARIABLES("Document";Var1;Var2;Var3;Var4)
 If(Var1="xxxxxx")
  `Document not found
 
 Else
  `Document found
 
 End if

This routine uses two different syntaxes in interpreted mode:

CLEAR VARIABLE(variable)

CLEAR VARIABLE("a")

In compiled mode, the first syntax of CLEAR VARIABLE(variable) reinitializes the variable (set to null for a numeric; empty string for a character string or a text, etc.), since no variable can be undefined in compiled mode.

Consequently, CLEAR VARIABLE does not free any memory in compiled mode, except in four cases: Text, Picture, BLOB and Array type variables.

For an array, CLEAR VARIABLE has the same effect as a new array declaration where the size is set to null.

For an array MyArray whose elements are of the Integer type, CLEAR VARIABLE(MyArray) has the same effect as one of the following expressions:

 ARRAY INTEGER(MyArray;0)
  `if it as a one-dimensional array
 ARRAY INTEGER(MyArray;0;0)
  `if it is a two-dimensional array

The second syntax, CLEAR VARIABLE("a"), is incompatible with the compiler, since compilers access variables by address, not by name.

The following commands have one common feature: they accept an optional first parameter [Table], and the second parameter can be a pointer.

ADD TO SETLOAD SET
APPLY TO SELECTIONLOCKED ATTRIBUTES
COPY NAMED SELECTIONORDER BY
CREATE EMPTY SETORDER BY FORMULA
CREATE SETFORM SET OUTPUT
CUT NAMED SELECTIONPAGE SETUP
DIALOGPrint form
EXPORT DIFPRINT LABEL
EXPORT SYLKQR REPORT
EXPORT TEXTQUERY
GOTO RECORDQUERY BY FORMULA
GOTO SELECTED RECORDQUERY SELECTION
GRAPH TABLEQUERY SELECTION BY FORMULA
IMPORT DIFREDUCE SELECTION
IMPORT SYLKRELATE MANY
IMPORT TEXTREMOVE FROM SET
FORM SET INPUT

In compiled mode, it is easy to return the optional [Table] parameter. However, when the first parameter passed to one of these commands is a pointer, the compiler does not know to what the pointer is referring; the compiler treats it as a table pointer.

Take the case of the QUERY command whose syntax is as follows:
QUERY({table{;formula{;*}})

The first element of the formula parameter must be a field.

If you write :

 QUERY(PtrField->=True)

the compiler will look for a symbol representing a field in the second element. When it finds the "=" sign, it will issue an error message, since it cannot identify the command with an expression that it knows how to process.

On the other hand, if you write:

 QUERY(PtrTable->;PtrField->=True)

or

 QUERY([Table];PtrField->=True)

you will avoid any possible ambiguity.

If you create your own 4DK# resources (constants), make sure that numerics are declared as Longints (L) or Reals (R) and character strings as Strings (S). Any other type will generate a warning.

 
PROPERTIES 

Product: 4D
Theme: Compiler

 
SEE ALSO 

Error messages
Optimization Hints
Typing Guide
Using Compiler Directives