Syntax Details

4D - Documentation   Français   English   German   4th Dimension 2004, Command Theme List   4th Dimension 2004, Command Alphabetical List   4th Dimension 2004, Constant Theme List   Back   Previous   Next

version 2003 (Modified)


The compiler expects that the usual syntactic rules for 4th Dimension 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


Ascii (character)

For commands operating on strings, only the Ascii 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 Ascii is a variable, the compiler will not be able to detect an error in compilation.

Communications


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)   

Structure access


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.

The two functions are not sufficient for the compiler to determine the data type of the result. In such cases, use a compiler directive to avoid any ambiguity.

Documents


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 4th Dimension:

   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.

Exceptions


IDLE

ON EVENT CALL (Method{; ProcessName})

ABORT

ON EVENT CALL

The IDLE command has been added to 4th Dimension 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 4th Dimension 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 4th Dimension is waiting passively for an event––for example, in a waiting loop––it is clear that there will be no call.

Example under Windows

      `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 4th Dimension, except in a method that has been called by one of the following commands: EXECUTE, APPLY TO SELECTION and APPLY TO SUBSELECTION. Try to avoid this situation.

Arrays


Seven 4th Dimension 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)

COPY 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.

SELECTION TO ARRAY, ARRAY TO SELECTION, DISTINCT VALUES, SELECTION RANGE TO ARRAY

As with 4th Dimension 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.

LIST TO ARRAY, ARRAY TO LIST

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

one-dimensional String arrays, and

one-dimensional Text arrays.

These commands do not require that the array passed as a parameter be declared. By default, the non-declared array will be typed as a Text array. If the array was previously declared as String or Text, these commands will follow your directives.

Using pointers in array-related commands

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.

Local arrays

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 4th Dimension 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)

Language


Get pointer(varName)

Type (object)

EXECUTE(statement)

TRACE

NO TRACE

Get pointer

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

Type (object)

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.

EXECUTE

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 can be replaced by a series of statements. Two examples are given below.

Given the following sequence:

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

It can be replaced by:

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

Below is another example:

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

Here, EXECUTE can be replaced with Case of:

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

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

TRACE, NO TRACE

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.

Variables


Undefined(variable)

SAVE VARIABLES(document;variable1{; variable2…})

LOAD VARIABLES(document;variable1{; variable2…})

CLEAR VARIABLE(variable)

Undefined

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 Compiled application command.

SAVE VARIABLES, LOAD VARIABLES

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

CLEAR VARIABLE

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.

Pointers with certain commands


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 SETOUTPUT FORM
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
INPUT FORM

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.

Constants


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.

See Also

Error messages, Optimization Hints, Typing Guide, Using Compiler Directives.


4D - Documentation   Français   English   German   4th Dimension 2004, Command Theme List   4th Dimension 2004, Command Alphabetical List   4th Dimension 2004, Constant Theme List   Back   Previous   Next