3.2_language_changes
3.2_language_changes
DataFlex 3.2 contains two sets of packages and FMAC/FLEX.CFL files; one to support legacy
character mode applications (like those you would create with DataFlex 3.1d, including both OOP
and Procedural styles) and one to support OOP style applications that would share DDO's with
Visual DataFlex and WebApp applications.
If you choose to use the new DDO style for your applications, you will need to make changes to
existing character mode application source code to bring it up to the standards set in VDF 6. We
have taken the section on Language Changes from the VDF 6 documentation for you to use as a
basic reference to the types of changes that may be involved.
Please note that not all of the information in this document is applicable to DataFlex 3.2.
If you are not using the new DDO style for your applications, using the traditional setpath.bat will
use the appropriate packages (for OOP style) and FMAC/FLEX.CFL (for both OOP and
procedural styles) and no application code changes are required.
Note: There are no plans to attempt support for hybrid mixes of the DDO and non-DDO packages
and FMAC/FLEX.CFL files. Do not attempt to mix these.
One of the goals of VDF 6 was to make the programming language easier to use. To achieve this
goal, four major changes were made:
1. A suggested syntax has been created for all commands: In cases where multiple
methods exist to accomplish the same goal, we now present a single “suggested”
approach. For example, when commands and functions exist that accomplish the same
thing (e.g., the Left command and function) we advise that you always use the function.
2. Stricter syntax checking is now enforced: Previous versions of DataFlex supported very
relaxed compiler syntax checking. This made the language confusing and made it much
harder to distinguish bad code from unusual code. We now enforce stricter and
consequently much more sophisticated syntax error checking. For example, the “to”
keyword is now required in any Set or Get statement. By requiring this keyword we can
now check that the “to” keyword is included, that it is included in the proper position and
that it is only included once.
3. A simplified syntax has been created: Some command syntax changes will make
programs easier to type, easier to read and less prone to error. For example, the Local
keyword is no longer required within a method. If a variable is declared within a method, it
is local. Another example of simplification is object referencing. You may now reference
an object by its simple name (e.g., Get piProp of oMyform to iVar) instead of it’s
expression access method (e.g., Get piProp of (oMyform(self)) to iVar)
4. We’ve identified many commands and techniques as being obsolete: We have identified
over 100 commands and numerous programming techniques as being obsolete and we
advise that you no longer use them. Note that these commands do not have removed
from existing programs – existing programs that use these commands will continue to run
properly. Documentation for obsolete commands has been moved into a section of the
Language Guide named Obsolete Commands, functions and other symbols. Each
obsolete command will contain a link to the command that should be used in its place.
You will find the advantages of these changes to be significant. It is possible that some existing
VDF programs will not compiler properly in VDF 6. In many cases, you will discover you’ve made
a programming error (and you will welcome the notification). In some cases older style coding,
while correct, will now be considered improper. While we provide a method to disable the new
changes allowing you to compile “old style” we encourage you in the strongest possible terms to
correct your programs and bring them up to date. We’ve performed this update on great deal of
internal code and have found the process to be relatively fast and easy.
To find out more about these changes you should refer to following VDF 6 documents:
• The Language Guide presents an overview of the DataFlex Language and should be
reviewed by all developers. This guide will be particularly useful to new developers.
• The Language Reference contains a section titled Obsolete Commands, Functions and
Other Symbols. Refer to this to see what commands are now obsolete and what
commands should be used in their place.
• Variables are intelligently scoped to determine if they are local or global. The Local
keyword is no longer required inside of methods.
• The object referencing parameter in Get/Set/Send commands allows you to use a simple
naming syntax of ObjectName instead of (ObjectName(Self)).
Here is an example of some of the commands and techniques that are now considered obsolete.
These are accompanied by their suggested replacement commands and techniques.
In DataFlex, there are numerous commands and functions that do the same thing (e.g., Left,
Right, Append, Pos). We recommend that you always use functions instead of commands.
Not: Left sText 20 to sValue
Use: Move (left(sText,20)) to sValue
Expressions
The use of logical operators is an area where there are many ways to accomplish the same
things. Below is some useful expression information and programming guidelines.
• In all cases expressions will evaluate to zero (false) or non-zero (true).
• If IntegerVariable; Parenthesis are not required for single operand expressions. The
single operand is usually an integer. If it’s zero, it is false. If it is non-zero, it is true.
If var….
If not var
• Use of indicators; Only use indicators when you must: Found, SeqEof, Err. Indicators can
be used in expressions but they must be enclosed within their own set of parenthesis.
If (found) ….
If ( (found) and (err) ) ….
If ( (found) and changed_state(self) and sVal<>””)
• Avoid global variables; Whenever possible use local variables within expressions and not
globals and particularly not indicators. Local integers can be used in place of indicators.
If you need to create a “variable” that is global to an entire object, define and use a
property – that’s what they are there for. Properties can be defined within objects and
within classes.
• The If statement can be followed by a single command or, if multiple commands are
needed, a Begin/End construct. The following does not require a Begin/End block
(although you may create one if desired):
If (SomeValue > SomeOtherValue) ;
Move SomeValue to SomeOtherValue
• Note that the use of the semi-colon as a command line separator is a valid and useful
technique.
Not: If (x eq 7)
Use: If (x=7)
• Do not use indicators. Use integers. If an integer evaluates to zero it is false, if non-zero it
is true.
Not: [IndOk] Move x to y
Use: If IntOk Move x to y
This should greatly reduce development time. Now, instead of tracking down problems within a
running program, you will have a much greater chance that the error will be reported at compile
time. The following sample should prove this point:
Class MyArray is An Array
Property Integer IsBusy public False
Object OldVals is an Array
End_Object
End_Class
How many errors can you see? In previous versions of Visual DataFlex, this sample will compile.
It might even run. Just about everything in it is wrong. Here are the problems:
1. Within a class you should only define properties within a method – usually construct
object.
10. The send Add_items syntax is wrong. The parameters belong after the object name.
The new compiler/fmac will catch all of these problems. In addition, changes have been made to
allow for simpler command syntax. The proper VDF6 code for the above example should be:
Class MyArray is An Array
Procedure Construct_Object
Forward Send Construct_Object
Property Integer pbIsBusy False
Object oOldVals is an Array
End_Object
End_Procedure
End_Class
The reporting of some errors can be relaxed. Items in this list marked with <Warning!> can be
relaxed by placing using the command Compiler_Warnings. This command can be used to turn
relaxed compiler checking on and off. The command is passed the parameter ON or OFF to
indicate if the compiler should relax its checking. Therefore placing the command
Compiler_Warning OFF at the top of a program will make it work the way it always did.
For example, it is possible, although highly unlikely, that the following syntax might be correct:
Procedure Add_Items
Integer iCnt
Get (MyProp(Self) to iCnt
:
End_Procedure
If this is the case, you could tell the compiler to allow this syntax by adding the command
“Compiler_Warning OFF” to the top of the program. Even better would be to surround the code as
follows:
Procedure Add_Items
Integer iCnt
Compiler_Warnings Off
Get (MyProp(Self) to iCnt
Compiler_Warnings On
:
End_Procedure
A better and recommended alternative would be to create syntax that is more clearly intentional.
The following code does not require relaxed error checking and it more clearly reflects the intent
of the programmer (even without comments).
Procedure Add_Items
Integer iCnt iMessage
Get MyProp to iMessage
Get iMessage to iCnt
:
End_Procedure
Even with Compiler_Warnings disabled, some new errors may be reported. These are errors that
are so serious that they can not be relaxed. They should be corrected immediately.
• If at desktop, it is a method of the Object class. In other words all objects will understand
the message via inheritance, not delegation. Same as “For BaseClass”. If you want an
method to reside on the desktop (and resolve via delegation) use “For DFDesktop”
• The same function name (get_xxxx) cannot be used for cross types
(internal/global/class/object-access). <Warning!>
• The same function name cannot be used with different parameter lists and types.
• End_Function / End_procedure checks for improperly nested child objects within the
method.
• A Return command inside a method will generate an error. If you must do this use the
command Gosub_return. <Warning!>
• Globals variables cannot be created within methods. The compiler will assume the
variable is local. If you must create a global within a method, use the new command
Global_Variable (e.g., Global_Variable Integer x). <Warning!>
Properties
• Check that name is valid. It cannot be used for other function type (internal/global/object-
access). If a class function, must have same parameter types
• Error if sent directly within a class (and not within method in the class) <Warning!>
6. Item Parameter is not required to precede the item value. Note that in
previous revisions of DataFlex the Item keyword was required for some
item based messages (e.g., value) but not for others (password_state). It
is now never required.
7. Item and Form based properties will provide a default item value (either
Current or 0) if the index parameter is omitted. This is discussed in
greater detail under Default Index values in Messages
• A simpler object naming syntax is supported. You may use ObjectName in place of
(ObjectName(self))
Expected Syntax:
Get msg {of obj} {{Field|File_field} param1...paramx} to Val
Set msg {of obj} {{Field|File_field} param1...paramx} to Val
Send msg {of obj} {param1...paramx}
Tolerated Syntax:
Get msg {of obj} {{Field|File_field|item} param1...paramx} to Val
Set msg {of obj} {{Field|File_field|item} param1...paramx} to Val...Valxx
Send msg {of|to obj} {param1...paramx}
Variables
• The local keyword is now optional. Variables declared within a method are local. If you
must place a global within a method use new command Global_Variable. <Warning!>
• If you already have variables declared within a method and you have not used the Local
keyword, it is really not clear what your intentions were. Most likely, you wanted this
variable to be local and you forgot the word local. Less likely, you actually wanted a
global variable. That variable will now be local. If you really wanted that variable to be
global you will receive a compiler error when you attempt to use the variable outside of
the method. This error will be your clue that you’ve declared your global variable within a
method. We advise you to move the variable outside of the method. Or, if you must,
preface the command with the global_variable keyword.
• The keyword self can now be used in place of current_object. The word self is more
commonly used across other object-oriented languages and it’s easier to type.
• An object name must uniquely identify an object. You cannot use the same name for a
function (either object function, global function, or built in function). If you try to use the
same name for cross purposes you will get an error. Previously you did not get errors for
this, but you should have - it was and is an error. <Warning!>
• When object name follows an “of” keyword (or “to” for send) the simple name of the
object can be used in place of the expression access method. The following two lines are
the same:
Get MyProp of oMyObj to iMyVar
Get MyProp of (oMyObj(self)) to iMyVar
The following sample shows how you can now access objects without using the
expression syntax.
Object oMyView is a ReportView
Procedure Doit
integer iLow iHi
Get Value of oLowRange to iLow
Get Value of oHiRange to iHi
Send RunReport of oMyReport iHi iLow
End_procedure
End_Object
In both cases above, the object oMyObj must be defined before it can be used. It
can be defined by creating the object or by using the register_object command.
• The move command allows you to move an object Id to a variable without needing to
place the object within an expression. The following two lines are the same:
Move oMyObj to hoMyObj
Move (oMyObj(self)) to hoMyObj
• If oMyObj is both the name of an object and the name of a variable (presumably a local
variable that is in scope) the variable name will have precedence. For example:
Object oObj1 is an Array
End_Object
• The simpler object addressing construct is handled by the compiler. The compiled result
of hObj and (hObj(self)) are identical. Both are access expressions. If you are going to
send a message to the same object many times within a method it is more efficient to
move the object handle to a variable (which is one evaluation) and to use the variable as
the message’s object handle.
Procedure Proc1
Integer hoArray
Integer iVal
Move oArray to hoArray // move object handle to variable
For iVal from 1 to 10000
Set value of hoArray iVal to “test Data”
Loop
End_Procedure
• You can only use this simplified syntax with the move command and with the object
handle of a message. You cannot use this syntax with parameters – you must use the full
expression syntax:
Note: Character-mode DataFlex does not use the “form_xxxx” interface described below
and does not support as many single-item entry objects (i.e. most entry forms and tables
are multi-item). Therefore in character mode DataFlex you are encouraged to always
provide the explicit item parameter in appropriate messages.
DataFlex has a number of messages that require an index parameter. These are often referred
to as “item based properties” where an item number (an index) is required to identify which item
data value should be queried. A better term for these item based properties would be collections.
A number of these messages have been turned into “auto-index” messages. If an index
parameter is not passed, a default value is provided. This was originally done to make it easy to
refer to the “current item” and was a feature of dubious value. This technique was applied to
much greater advantage in VDF where objects existed that internally were multi-item but from a
usage (and interface) point of view were always single item (item 0). It was not intuitive to have to
apply index values when there was always one and just one value, and its index was always
zero.
In VDF4 and 5, some multi-item messages (e.g., get/set Value) were auto-indexed and did not
require an index parameter (e.g., Get Value of hoMyForm to sVar). While other multi-item
messages were not and did require an index parameter (e.g., Set password_state of hoMyForm
to True). This inconsistency created confusion and errors.
In VDF6 a more consistent set of auto-index properties has been defined and is listed below. If an
index parameter is omitted a default value (usually 0) will be provided. This means that the
following two code lines are identical:
Set Value of oForm to sValue // suggested
Set Value of oForm 0 to sValue
In the above example, a form is a single item based object so you are encouraged to not use an
explicit index value. The following example shows two identical code lines. Since the array is
multi-item based, you are encouraged to always use explicit index values:
Set Value of oArray to sValue
Set Value of oArray 0 to sValue // suggested
• Single item objects (e.g., Form, Checkbox, ComboForm, dbForm) should never pass an
index number as a parameter. Allow VDF to provide index 0 for you.
• Multi item objects (e.g., Arrays, Grids, dbGrids) should always pass an index number.
Even if you know the value is zero or current_item explicitly pass the value. Never allow
VDF to apply a value for you.
The difference between current-item based and form based messages are historical. Since we
only recommend that you omit the index parameter on single item objects the current-item should
always be zero. This means that both types of messages should be treated the same.
To allow the compiler to perform maximal error checking it is assumed that all of the above
messages will support one and only one parameter to the left of the To keyword. This allows the
compiler to recognize compiler errors in all of the following statements:
Set Value of oArray to 7 “My Value” // index in wrong location
Set Value of oArray 8 “My Value” // missing To
Set Value of oArray iVal // is iVal index or value?
Set Value 0 to iVal of oArray // object id in wrong place
Set Value oArray iVal “test” // what does this mean
The older compiler would permit most of the constructs creating programs that were quite difficult
to maintain.
A couple of messages are exceptions to this rule. The following index messages requires two
parameters to the right of the To keyword. They exist for historical reasons only. No new
messages will be created in this style. Those messages are: Item_Option, Form_Color,
Form_Style, and Form_Extended_Style.
Finally, note that the use of messages with optional parameters is an internal technique. Do not
extend this technique to your own custom messages.
Case Statement
DataFlex case statement has been shipped with DataFlex since version 3.1. It was not
documented and the package “case.mac” had to be used in a program to access it. It is now part
of the precompiled packages. The syntax is discussed elsewhere (see Language Guide and
Reference).
If you are using some other case command in your programs you are encouraged to change your
applications and use the official command provided with the product.
If you must use some other case command, you can disable the DataFlex case command by
commenting out the line “use case.mac” in dfbase.pkg and pre-compiling. This should be a
temporary solution. Next revision this disabling feature will not be supported.
• The DDO’s field validations did not perform Required and Find_Req validations. In visual
views, the DEO would normally perform these operations but in batch processes these
validations were skipped. The validation now occurs as expected. This has caused a
certain amount of confusion, which is discussed below.
• The new message File_Field_Entry was created that moves data into the DDO’s field
buffer in much the same way keyboard entry does. It properly disables entry into fields
that are No_Put (both regular and foreign field), it performs capslocks as needed, and it
performs autofinds as needed. In some batch processing situations you would want to
use this message instead of set File_Field_current_value.
• The new message File_field_Find was created which performs a find similar to the
Item_Find message except that data for the find is moved into the DDO buffer and not
the DEO buffer.
• Within data dictionary objects, the message OnConstrain should be used in place of the
Begin_Constraints/End_Constraints command (or the Constrain procedure).
IMPORTANT: In VDF, the data dictionary objects only directly support date, string and numeric
fields. Text, binary and overlap fields are not supported and attempting to access them from
within the DD is an error. The most likely improper use of this would be to get or set the field
value with the field_current_value message. In previous versions of the DD packages these
errors were handled by ignoring the message and doing nothing. While the error was not
reported, the DDO was definitely not doing what you wanted it do. The right thing to do was to
report the error so in revision 5.0.6, these errors were reported as “Extended Field not defined”
errors. This caused confusion because programs that previously appeared to be working now
generated error messages. These errors occurred under the following conditions:
1. You attempted to access a text or binary field with the messages Get/Set
Current_field_value, Get/Set File_field_current_value or Get Field_changed_value. Since
these fields are not supported, in all cases, this is an error. You should look at your code
and make the required corrections.
2. You are improperly using overlap fields. You should not directly access overlap fields with
DDO messages. It is expected that you will use the underlying (primary) fields that make
up the overlap. In particular:
• You should never mark any overlap fields as a Key-field. It doesn’t work.
Instead, you should mark each underlying field as a key-field. A key field
can consist of multiple fields.
• You should not use overlap fields with field options, validation tables,
entry, exit or validation messages. You should use the underlying fields
instead.
Because this has caused so much confusion, the packages have been changed, so that a new
runtime error message will be generated if you attempt to improperly use an overlap field. The
reported error will be “999 - Invalid use of overlap with DD.” When displayed, the overlap file and
field number will also be displayed. This is a bug in your program that must be fixed. In most
cases, you will fix this by loading the Data Dictionary Builder, removing the DD field settings from
the overlap field and adding the field setting to the underlying fields.
If you have been improperly accessing text or binary fields you will receive the error message
“999 - Extended Field not defined in DD”. The offending file and field will also be reported with the
error. You will want to fix this error in your code.
IMPORTANT: In previous versions of VDF, Required and Find_Required validations were not
performed if the field needing the validation was not visually represented in a view. This validation
loophole has now been closed. This has caused some problems with existing programs. The
mostly likely cause of these problems and their solutions are:
• When a child field relates to a parent field, the required and find_req should always be
applied to the parent and not the child field. Setting the child-field is an error. In previous
versions of VDF this error went undetected. In VDF6 you will want to correct this.
• You should never set overlap fields as required or find_req.
• Do not set overlap fields as key-fields. Instead, you should set each underlying field that
makes up the overlap as a key field.
• If you are saving a new parent record at the same time you are trying to save a new child
record you may receive a required validation error. This occurs because the parent is
now treated as a foreign file. If any of the parent’s foreign validations are required or
find_req (and they probably are) you will get an error message when you attempt to save
the child record (which is attempting to also save a new parent record). The solution is to
set the parent’s allow_foreign_new_save_state to true. This tells the parent DDO that it
should not treat the file as a foreign file.
Field_Validate now performs a Required and Findreq validation as needed. Previously data-entry
objects only performed these validations which presented a problem with batch processing. Two
new private functions Valdiate_Required and Validate_FindReq were created to support this
change.
IMPORTANT: It is possible that the change in Field_Validate may alter the way your program
works. This most likely change will be that you will see a required or find-required error occur
when previously none occurred. In previous revisions of the data-dictionary required and find-
required validations were not performed unless a DEO existed for the field within the view. This
was a defect. It meant that these validation tests were never performed during batch processes
and that they might not be performed during normal data entry (if the field were not present as a
visual DEO item).
If you start encountering errors, you may wish to check your DD field settings. Your logic may be
incorrect. Find_Required is most often used with foreign files (parent files). If you are
encountering new validation problems with find_required keep in mind that setting the
Validate_Foreign_File_state property to false can disable the foreign (parent) field validation. This
property is normally set within a DD object and not class and is set in the main DDO and not the
parent DDO. It can be set for an entire view or could be set conditionally by augmenting the
function Request_Validate.
These functions are now passed an additional integer parameter (bNoStop) which determines if
the validation should end when the first error is encountered. These are private messages, which
should not be sent or augmented, and therefore this change should be transparent to all
applications. If you have used these messages you will need to change your code.
Function Data_Set
Previously this function only traversed upwards when looking for the DDO owner of the passed
file. This has been changed. If the owner DDO is not found during the upward sweep it will
traverse in a downward direction. Since DDOs are almost always found in an upwards sweep,
this should have no impact on applications.
It is only expected that you will use these messages during batch processing.
The error object handler processes errors by sending the message Error_report. In previous
runtimes, two parameters were passed to this procedure, errorInfo (integer) and errorText
(string). ErrorInfo was a complex integer containing both error number and line number. This
“packing” scheme only works with programs with fewer than 64k lines. When programs contain
more than 64k lines error will not be properly reported.
This has been fixed in the runtime. The Error_report message now receives three (non-packed)
variables. The new format for error_report is:
procedure Error_Report integer iErrNum integer iErrLine string sErrMsg
IMPORTANT: If you have created any augmentations of Error_report you must change your
programs. Your procedure must now receive three parameters and you must make sure you
forward three parameters. For example, assume that you had the following procedure:
Procedure Error_Report integer iErrInfo string sErrMsg
integer hErr
integer iErrNum iErrLine
If (error_processing_state(self)=False) Begin
Set Error_processing_State to True // prevents recursion
Move (Hi(iErrInfo)) to iErrNum
Move (Low(iErrInfo)) to iErrLine
Send Log_this_Error iErrNum iErrLine iErrMsg
Get Old_Error_Object_Id to hErr
Send Error_Report to hErr iErrInfo sErrMsg
Set Error_processing_State to False
End
End_procedure
If you are sending the message Error_report to trigger an error you will also need to change your
parameter list. However, you should not be using the technique at all! If you wish to generate an
error you should do so with the Error command. The message error_report should only ever be
sent within the error_report procedure. Some developers have been using this improper
technique as a means on generating errors within text longer than 40 characters. Now that this
40-character limit has been removed you should no longer need to use this technique.
IMPORTANT: If you find that you are encountering nonsense error messages such as error
numbers of 0 and error text that makes no sense, then your program probably contains calls to
error_report or augmentations of error_report, and you did not change your source to handle the
additional parameter.
Back to Runtime and Package Changes