4D v13.4Typing Guide |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
4D v13.4
Typing Guide
Typing Guide
This section describes the main causes of typing conflicts on variables, as well as ways to avoid them. Simple data type conflicts can be summarized as follows:
The simplest data type conflict is one that stems from a single variable name designating two different objects. Suppose that, in an application, you write: Variable:=5 and that elsewhere, in the same application, you write: Variable:=True This generates a data type conflict. The problem can be solved by renaming one of the variables. Suppose that, in an application, you write: Variable:=5 and that elsewhere, in the same application, you write: C_BOOLEAN(Variable) Since the compiler scans the directives first, it will type Variable as Boolean, but when it finds the statement: Variable:=5 it detects a data type conflict. You can solve the problem by renaming your variable or modifying the compiler directive. Using variables of different data types in one expression creates inconsistencies. The compiler points out incompatibilities. Here is a simple example: Some functions return variables of a very precise data type. Assigning the result of one of such variables to a variable already typed differently will cause a data type conflict if you are not careful. IdentNo:=Request("Identification Number") `IdentNo is data type Text In this example, you create a type conflict in the third line. The solution consists in controlling the behavior of the variable. In some cases, you must create an intermediate variable that uses a different name. In other cases, such as this, your method can be structured differently: Declaring the same variable through two conflicting compiler directives constitutes a retyping. If, in the same database, you write: the compiler detects the conflict and reports an error in the error file. Typically, you can solve the problem by renaming one of the variables. Keep in mind that a data type conflict can arise concerning the use of C_STRING if you modify the maximum string length. Thus, if you write: C_STRING(5;MyString) the compiler identifies a conflict because it must provide an adequately-sized location when declaring String variables. The solution is to use a compiler directive that gives the maximum length, since, by default, the compiler will accept a shorter length. You can write: C_STRING(7;String) Note: If you have written C_STRING(7;String) twice, i.e.: C_STRING(7;String) the compiler will nevertheless accept the directives; the second directive is simply redundant. Data type conflicts involving local variables are identical to those in process or interprocess variables. The only difference is that there must be consistency only within a specified method. $Temp:="Flowers" and then $Temp:=5 However, you can write: $Temp:="Flowers" in method M1, and: $Temp:=5 in method M2, because the scope of local variables is the method itself and not the entire database. Conflicts concerning an array are never size-related. As in uncompiled databases, arrays are managed dynamically. The size of an array can vary throughout methods, and you do not have to declare a maximum size for an array. Therefore, you can size an array to null, add or remove elements, or delete the contents. You should follow these guidelines when writing a database intended for compilation:
If you declare an array as an Integer array, it must remain an integer array throughout the database. It can never contain, for example, Boolean type elements. ARRAY INTEGER(MyArray;5) the compiler cannot type MyArray. Just rename one of the arrays. In an uncompiled database, you can change the number of dimensions in an array. When the compiler sets up the symbol table, one-dimensional arrays and two-dimensional arrays are managed differently. ARRAY INTEGER(MyArray1;10) However, you can write the following statements in the same application: ARRAY INTEGER(MyArray1;10) The number of dimensions in an array cannot be changed in a database. However, you can change the size of an array. You can resize one array of a two-dimensional array and write: ARRAY BOOLEAN(MyArray;5) Note: A two-dimensional array is, in fact, a set of several one-dimensional arrays. For more information, refer to the Two-dimensional Arrays section. String arrays follow the same rules as fixed strings, for the same reasons. ARRAY STRING(5;MyArray;10) the compiler detects a length conflict. The solution is simple: declare the maximum string length. The compiler automatically handles shorter length strings. When using commands such as COPY ARRAY, LIST TO ARRAY, ARRAY TO LIST, SELECTION TO ARRAY, SELECTION RANGE TO ARRAY, ARRAY TO SELECTION, or DISTINCT VALUES, you may change, voluntarily or not, the data types of elements, the number of dimensions, or, in a String array, the string length. You will thus find yourself in one of the three situations previously mentioned. If you want to compile a database that uses local arrays (arrays only visible by the methods that created them), you must explicitly declare them in 4D before using them. ARRAY INTEGER($MyArray;10) Variables created in a form (e.g., buttons, drop-down list boxes, and so forth) are always process or interprocess variables. In an interpreted database, the data type of such variables is not important. However, in compiled applications, it may have to be taken into consideration. The rules are, nevertheless, quite clear:
The following form variables are typed as Real by default:
Note: The Ruler, Dial and Thermometer form variables are always typed as Reals, even if you choose Long integer as the Default Button Type in the Preferences. For one of these variables, the only data type conflict that could arise would be if the name of a variable were identical to that of another one located elsewhere in the database. In this case, rename the second variable. A graph area is automatically data type Graph (Longint). This variable never creates a data type conflict. For a Graph type variable, the only possible data type conflict that could arise would be if the name of a variable were identical to that of another one located elsewhere in the database. In this case, rename the second variable. A plug-in area is always a Longint. There can never be a data type conflict. These variables are of the following types:
These variables are divided into two categories:
When you use pointers in your database, you take advantage of a powerful and versatile 4D tool. The compiler preserves all the benefits of pointers. A pointer can point to variables of different data types. Do not create a conflict by assigning different data types to a variable. Be careful not to change the data type of a variable to which a pointer refers. Here is an example of this problem: Variable:=5.3 In this case, your dereferenced pointer is a Real variable. By assigning it a Boolean value, you create a data type conflict. If you need to use pointers for different purposes in the same method, make sure that your pointers are defined: A pointer is always defined in relation to the object to which it refers. That is why the compiler cannot detect data type conflicts created by pointers. In case of a conflict, you will get no error message while you are in the typing phase or in the compilation phase. This does not mean that the compiler has no way to detect conflicts involving pointers. The compiler can verify your use of pointers when you check the Range Checking option in the compilation Preferences (see the Design Reference manual). During compilation, the compiler analyzes the definitions of the plug-in commands used in the database, i.e. the number and type of parameters of these commands. There is no danger of confusion at the typing level if your calls are consistent with the declaration of the method. Certain plug-ins, for example 4D Write, implement commands that implicitly call 4D commands.
For the compiler to take these parameters into account, you must make sure that they have been typed, either by a compiler directive, or by their usage in the method. If they have been used procedurally, the usage has to be explicit enough to be able to deduce the type clearly. 4D can be used to create and work with components. A 4D component is a set of 4D objects representing one or more functionalities and grouped in a structure file (called the matrix database), that can be installed in different databases (called host databases). A host database running in interpreted mode can use either interpreted or compiled components indifferently. It is possible to install both interpreted and compiled components in the same host database. On the other hand, a host database running in compiled mode cannot use interpreted components. In this case, only compiled components can be used. An interpreted host database containing interpreted components can be compiled if it does not call any methods of the interpreted component. If this is not the case, a warning dialog box appears when you attempt to compile the application and compilation is not possible. A naming conflict can occur when a shared project method of the component has the same name as a project method of the host database. In this case, when the code is executed in the context of the host database, the method of the host database is called. This means that it is possible to “mask” the method of the component with a custom method (for example, to obtain a different functionality). When the code is executed in the context of the component, the method of the component is called. This masking will be indicated by a warning in the event of compilation of the host database. If two components share methods having the same name, an error is generated when the host database is compiled. For more information about components, please refer to the Design Reference manual. The handling of local variables follows all the rules that have already been stated. As with all other variables, their data types cannot be altered while the method executes. In this section, we examine two instances that could lead to data type conflicts:
A variable cannot be retyped. However, it is possible to use a pointer to refer to variables of different data types.
MemSize function, only in interpreted mode (example for Macintosh) $Size:=Size of array($1->) In the above method, the data type of $0 changes according to the value of $1; therefore, it is not compatible with the compiler. MemSize function in interpreted and compiled modes (example for Macintosh) Here, the method is written using pointers: $Size:=Size of array($1->) Here are the key differences between the two functions:
The compiler manages the power and versatility of parameter indirection. In interpreted mode, 4D gives you a free hand with numbers and data types of parameters. You retain this freedom in compiled mode, provided that you do not introduce data type conflicts and that you do not use more parameters than you passed in the calling method. As an example, consider a function that adds values and returns the sum formatted according to a format that is passed as a parameter. Each time this method is called, the number of values to be added may vary. We must pass the values as parameters to the method and the format in the form of a character string. The number of values can vary from call to call. This function is called in the following manner: Result:=MySum("##0.00";125,2;33,5;24) In this case, the calling method will get the string “182.70”, which is the sum of the numbers, formatted as specified. The function's parameters must be passed in the correct order: first the format and then the values. Here is the function, named MySum: $Sum:=0 This function can now be called in various ways: Result:=MySum("##0.00";125,2;33,5;24) As with other local variables, it is not necessary to declare generic parameters by compiler directive. When required (in cases of ambiguity or for optimization), it is done using the following syntax: C_INTEGER(${4}) This command means that all parameters starting from the fourth (included) will be addressed by indirection and will be of the data type Integer. $1, $2 and $3 can be of any data type. However, if you use $2 by indirection, the data type used will be the generic type. Thus, it will be of the data type Integer, even if for you it was, for instance, of the data type Real. Note: The compiler uses this command in the typing phase. The number in the declaration has to be a constant and not a variable. Some 4D variables and constants are assigned a data type and an identity by the compiler. Therefore, you cannot create a new variable, method, function or plug-in command using any of these variables or constant names. You can test their values and use them as you do in interpreted mode. Here is a complete list of 4D System Variables with their data types.
When you create a calculated column in a report, 4D automatically creates a variable C1 for the first one, C2 for the second one, C3 and so forth. This is done transparently. A complete list of the predefined constants in 4D can be found using the List of constant themes. 4D constants are also displayed in the Explorer in Design mode. |
PROPERTIES
Product: 4D SEE ALSO
Error messages |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||