You are on page 1of 139

LANGUAGE GUIDE

Revision 7

Technical Support: Internet Address (URL): http://www.dataaccess.com Newsgroup: news//news.dataaccess.com/dac-public-newsgroups.visual-dataflexsupport FTP Site: ftp.dataaccess.com e-mail Address: support@dataaccess.com Revision Date: August 9, 2000 Part Number: 006900.LG

COPYRIGHT NOTICE Copyright 2000 DATA ACCESS CORPORATION. All rights reserved. No part of this publication may be copied or distributed, transmitted, transcribed, stored in a retrieval system, or translated into any human or computer language, in any form or by any means, electronic, mechanical, magnetic, manual, or otherwise, or disclosed to third parties without the express written permission of Data Access Corporation, Miami, Florida, USA. DISCLAIMER Data Access Corporation makes no representation or warranties, express or implied, with respect to this publication, or any Data Access Corporation product, including but not limited to warranties of merchantability or fitness for any particular purpose. Data Access Corporation reserves to itself the right to make changes, enhancements, revisions and alterations of any kind to this publication or the product(s) it covers without obligation to notify any person, institution or organization of such changes, enhancements, revisions and alterations. TRADEMARKS DataFlex is a registered trademark of Data Access Corporation. All other company, brand and product names are registered trademarks or trademarks of their respective holders.

TABLE OF CONTENTS
Chapter 1 - Introduction .....................................................11
What this book contains .......................................................... 11 Manual Conventions ................................................................ 11

Chapter 2 - Tokens..............................................................13
Reserved Words ....................................................................... 13 Numbers.................................................................................... 13
Integer Tokens ....................................................................................13 Number Tokens...................................................................................14 Real Tokens.........................................................................................14 Hexadecimal Tokens ..........................................................................14

Character Strings ..................................................................... 15 Date Tokens .............................................................................. 15 Comments................................................................................. 15

Chapter 3 - Types................................................................17
Integer ....................................................................................... 17 Number...................................................................................... 17 Real ........................................................................................... 17 Boolean ..................................................................................... 18 Date ........................................................................................... 18 Time........................................................................................... 18 TimeSpan .................................................................................. 19 3

DateTime ...................................................................................19 String .........................................................................................19 Handle........................................................................................19 Array Types ...............................................................................20 Data File Type ...........................................................................20 Structured Types ......................................................................20 Automatic Type Conversion.....................................................20

Chapter 4 - Variables and Constants.................................23


Declaring Variables...................................................................23
Local Variables....................................................................................24 Global Variables..................................................................................24 Data Files .............................................................................................25 Structure Variables.............................................................................26

Declaring Constants .................................................................26


Enumerated Constants ......................................................................26

Chapter 5 - Expressions .....................................................29


Expression Syntax....................................................................29
Examples .............................................................................................31 Boolean Expressions .........................................................................31 Rules of Operator Precedence ..........................................................32

Typecasting of Expressions ....................................................32

Chapter 6 - Statements .......................................................35


Simple Statements....................................................................35
Assignment Statements.....................................................................35

Continuing a Statement on the Next Line ........................................35

Compound Statements ............................................................ 36 Conditional Statements ........................................................... 37


If ............................................................................................................37 Case .....................................................................................................38

Looping Statements ................................................................. 39


While ....................................................................................................39 Repeat ..................................................................................................39 For ........................................................................................................40

Chapter 7 - Procedures and Functions .............................43


Procedures ............................................................................... 43
Declaring Procedures.........................................................................43 Calling Procedures .............................................................................44

Functions .................................................................................. 44
Declaring Functions ...........................................................................44 Calling Functions................................................................................46

Forward Declarations............................................................... 46 Design Considerations ............................................................ 47 DataFlex built-in Function Library........................................... 47


Math Functions ...................................................................................47 String Functions .................................................................................48 Time and Date Functions ...................................................................49 Type Coercion Functions...................................................................51 Miscellaneous Functions ...................................................................52

Chapter 8 - Classes.............................................................53
5

Class Declaration......................................................................53 Properties ..................................................................................54


Declaring Properties...........................................................................54 Setting Property Values .....................................................................55 Reading Property Values ...................................................................56 Forward Declaring Properties ...........................................................58

Methods.....................................................................................58
Declaring Procedure Methods...........................................................59 Declaring Procedure Set Methods ....................................................61 Declaring Function Methods .............................................................62 Forward Declaring Methods ..............................................................63 Event Methods ....................................................................................64 Calling Procedure Methods ...............................................................65 Calling Procedure Set Methods ........................................................66 Calling Function Methods..................................................................69 Constructors and Destructors...........................................................71 Augmenting Inherited Methods.........................................................72

Private Objects..........................................................................75 The Self Keyword......................................................................76 Multiple-Inheritance ..................................................................76

Chapter 9 - Objects .............................................................79


Object Declaration ....................................................................79
Declaring New Properties ..................................................................80 Declaring New Methods .....................................................................80 Forward Declaring Objects ................................................................81

Object Nesting ..........................................................................81 6

Delegation............................................................................................84

Sending Messages to Objects ................................................. 87


Sending a Message to Yourself.........................................................87 Sending a Message to Another Object .............................................88 Passing Object Handles as a Parameter ..........................................90 Relative Object Name Access ...........................................................90 Long and Short Object Names ..........................................................93 Other Object Access Methods...........................................................94

Chapter 10 - Programs .......................................................97


Using Packages........................................................................ 97 Simple Programs...................................................................... 97 Pre-Compilation........................................................................ 98

Chapter 11 - Sequential File Input and Output ...............101


Introduction ............................................................................ 101 Opening Sequential I/O Files ................................................. 101
Appending Data to an Output File...................................................102

Reading and Writing Data ...................................................... 102


Reading Data .....................................................................................102 Writing Data.......................................................................................105 Random Access ................................................................................106 Using Explicit I/O Channels .............................................................107

Closing Sequential I/O Files .................................................. 107

Chapter 12 - Accessing Class Attributes with Expressions.......................................................................109

Reading Properties using Expressions.................................109 Calling Function Methods using Expressions ......................111

Chapter 13 - Advanced Data Types .................................115


Address ...................................................................................115 BigInt .......................................................................................115 Char .........................................................................................115 Currency..................................................................................116 Decimal....................................................................................116 Float .........................................................................................116 Short ........................................................................................116 UBigInt.....................................................................................117 UChar.......................................................................................117 UInteger ...................................................................................117 UShort......................................................................................117 Structured Types ....................................................................117
Declaring Structure Variables .........................................................119 Accessing Data in a Structure Variable..........................................119

Appendix A - Visual DataFlex Reserved Words .............121 Appendix B - Naming Conventions .................................129 Appendix C - Visual DataFlex Specifications .................133
Features .............................................................................................133

Requirements..........................................................................133 8

Platforms................................................................................. 134 Structure ................................................................................. 134 Connectivity Kits .................................................................... 134 Database Specifications (All Databases used with VDF)..... 134 DataFlex Database Record & Table Specifications.............. 134 DataFlex Database Index Specifications .............................. 135 DataFlex Database Field Specifications ............................... 135 Application / Coding............................................................... 136 Database Specifications (All Databases used with VDF)..... 137 DataFlex Database Record & Table Specifications.............. 137 DataFlex Database Index Specifications .............................. 138 DataFlex Database Field Specifications ............................... 138 Application / Coding............................................................... 139 Visual DataFlex Program File ................................................ 140 Argument Size ........................................................................ 140

Visual DataFlex Language Guide

Chapter 1 - Introduction
This manual is about Visual DataFlexs object oriented programming language. It presents a formal definition of the syntax and use of the Visual DataFlex language. You can also find detailed information about the syntax of specific DataFlex commands in the Visual DataFlex Language Reference manual and on-line help.

What this book contains


This manual presents several kinds of information:

Introduction

The first ten chapters define the Visual DataFlex language, examining each element of a program in detail and how it fits into the structure of a program. The remaining chapters present technical information on various specific programming operations such as file input and output, the Database API, and advanced function method calling.

Manual Conventions
Typefaces and Symbols Used in this Manual Special typefaces and symbols are used when describing the syntax of the Visual DataFlex programming language in this manual. These symbols are described in the following table.

TYPEFACE OR SYMBOL
Monospace type

MEANING
Monospaced text is used to represent programming code and code elements as it must be typed. It is also used for all the following symbols. Square brackets are used to enclose optional syntax. You should not type square brackets verbatim. Text within {} braces represents Visual DataFlex identifiers such as variable names, object names, or method names.

[]

{indentifier}

11

Visual DataFlex Language Guide

Chapter 2 - Tokens
Tokens are the smallest units of text in a Visual DataFlex program. A Visual DataFlex program is made up of tokens and separators. A separator is a blank, tab character or a new line/carriage return. Each token must be separated by one or more separators.

Reserved Words
Visual DataFlex reserved words are the tokens used as commands, predefined functions, pre-defined constants, pre-defined variables and compiler directives. Reserved words in Visual DataFlex are not case sensitive, so you can mix uppercase and lowercase letters in your programs. Reserved words cannot be redefined. For example you cannot define a variable called while because while is the Visual DataFlex reserved word for a looping statement. Refer to Appendix A - Visual DataFlex Reserved Words on page 121 for a complete listing.

Tokens

Numbers
Visual DataFlex can represent three different types of numbers, they are: Integer, Number and Real.

Integer Tokens
Integer tokens are formed by combining numeric digits, and an optional minus sign. These represent whole numbers in the range 2147483647 to 2147483648. Numbers outside this range cannot be represented as an integer token. Since integers are whole numbers they cannot contain decimal places. Examples of integer tokens are:
2800 0 -1000000

These tokens are not integers:

13

Chapter 2
-2800.01 12345678901234567890 range // this number contains decimal places // this number exceeds the maximum

Number Tokens
Number tokens are formed by combining numeric digits, a decimal point, and an optional minus sign. These represent real numbers in the range +/ 99999999999999.99999999. Examples of number tokens are:
1000.55 -0.0000004

Tokens

Real Tokens
Real number tokens are used to represent numbers in a floating-point format. A real number is formed by combining mantissa and exponent parts using the special symbol e (scientific notation) to delimit the exponent. The format of each of the mantissa and exponent parts is the same as a DataFlex Number token (but the range for each is smaller). The exponent is written after the mantissa without any intervening separators. Examples of real tokens are:
1.55e003 -2.0e-002 // 1.55 x 10 to the power of 3, or 1,550 // -2 x 10 to the power of 2 or 2/100

DataFlex can represent real numbers in the range +/-1.0 times 10 to the power of +/-306. Real numbers are accurate to a precision of 16 significant digits, i.e., the mantissa can be expressed as a number up to 15 digits following the decimal point.

Hexadecimal Tokens
Hexadecimal tokens are used to denote integer-type numbers in hexadecimal format. A hex number is formed by writing a dollar symbol ($) followed by 1 to 8 hexadecimal digits. Hex numbers must be within the range $00000000 to $FFFFFFFF. Examples of hex tokens are:
$1F $B200A1

14

Visual DataFlex Language Guide

Character Strings
A DataFlex string token is a sequence of zero or more typeable characters, written together and enclosed by quotation marks ( or ). Visual DataFlex allows you to use either single quote (') or double quote (") characters to delimit a string. Whichever type you use must match at both ends of the string. This allows you to type a string with embedded quote marks, so long as the embedded quotes are different to those used to delimit the string. Examples of string tokens are:
"The quick brown fox" jumped over the lazy dog... 3 times! "Frank says hello." Susan says "Hi". ""

Tokens

Date Tokens
A DataFlex date token is represented by a sequence of numbers and separators that depict the day, month and year of the specific date. The ordering of the day, month and year digits and the type of separator that is used is configurable, and transparent. By default, Visual DataFlex represents dates in the following format: mm/dd/yyyy, where mm represents the month (1-12), dd the day (1-31 or whatever the maximum day is for a given month) and yyyy is the year (0001 2200). Visual DataFlex can be configured to use European dates in the format dd/mm/yyyy or military dates in the format yyyy.mm.dd. Examples of date tokens are:
12/20/1990 03/28/1961 // USA format representing December 20, 1990 // USA format representing March 28, 1961

Comments
A comment is constructed by typing a double-slash (//) followed by the comment text. All characters from the double-slash to the end of the line are part of the comment. Examples of comments are:

15

Chapter 2
// This is a comment Move 100 To iCount statement // This is a commented assignment

Comment constructs are ignored by the compiler.

Tokens

16

Visual DataFlex Language Guide

Chapter 3 - Types
When you declare a variable, you must state its type. A variables type determines the set of values it can have and the operations that can be performed on it. Visual DataFlex Types fall into three categories: Simple Types String Types Structured Types

Simple Types define an ordered set of values, String Types define a set of zero or more characters and Structured Types are composed of component types.

Types

Integer
Integer is a simple type that is used to declare variables for storing Integer tokens.

TYPE
Integer

RANGE
-2147483647...2147483647

Number
Number is a simple type that is used to declare variables for storing Number tokens. Number variables are ideal for storing and calculating monetary values.

TYPE
Number

RANGE
-99999999999999.99999999.. 99999999999999.99999999

Real
Real is a simple type that is used to declare variables for storing Real Number tokens.

17

Chapter 3 TYPE
Real

RANGE
+/-1.0 e +/-306

Boolean
The Boolean type is a simple type that is used for declaring variables for storing Boolean values. Boolean values are denoted by the predefined constants True and False. The Integer value of False is 0 and the Integer value of True is 1.

TYPE
Integer

RANGE
0,1

Types

Date
Date is a simple type that is used to declare variables for storing Date tokens.

TYPE
Date

RANGE
01/01/0001 ... 01/01/2500

Time
The Time type is a structured type that corresponds to an SQL Time_Struct as defined in ODBC.
Type Time_Struct Field Hour Field Minute Field Second End_Type as uShort as uShort as uShort

Refer to the Advanced Data Types section for more information on Structured Types and the UShort type. Time types are used for declaring variables for storing Time tokens.

TYPE
Structure

RANGE
00:00:00 to 23:59:59

18

Visual DataFlex Language Guide

TimeSpan
The TimeSpan type is a structured type with the same internal structure as a DateTime. Only Days, Hours, Months, and Seconds are stored. TimeSpan types are used for declaring variable for storing the difference of two DateTime values, i.e., the subtraction of one DateTime value from another.

TYPE
Structure

RANGE
65535 days.

DateTime
The DateTime type is a structured type that corresponds to an SQL Timestamp_Struct as defined in ODBC. DateTime types are used for declaring variables for storing DateTime tokens.

Types

TYPE
Structure

RANGE
From Jan 1, 1900. A double precision number is used internally.

String
The String type is used to declare variables for storing Strings. Visual DataFlex allocates one byte of storage per character contained in the string. The size of a string variable is dynamically allocated at runtime as the string value changes in length up to a maximum of 16383 characters. However, you can use the Set_Argument_Size command to increase the maximum to 2GB. Note: Global string variables can only contain a maximum of 80 characters by default and an absolute maximum of 255 characters. The Set_Argument_Size command has no effect on global strings. Refer to the Language Reference On-line help for more information on the Set_Argument_Size command.

Handle
Handle is a simple type that is used to declare variables for storing references to some other identifier, such as an object.

19

Chapter 3 TYPE
Handle

RANGE
0..4294967296

Array Types
Visual DataFlex does not have a specific Array type. However, it does provide a special Array class. The Array class allows you to create powerful array objects to perform all of your array data handling. Refer to the Class Reference On-line help for more information on the DataFlex Array class.

Data File Type

Types

The Data File type is a structured type that is used to access records of a database file. The structure of a data file record is defined by a set number of fields that can be of different types. Each data file in your program will have a file definition. The file definition declares each fields name and type. The notation for accessing a data file field is a combination of the file name, a period, and the field name, for example:
Customer.Name file Customer.Phone data file Order.ODate file // Refers to the name field of a customer data // Refers to the ph. no. field of a customer // Refers to the date field of a order data

Note: Refer to the Database Builder On-line help for information on creating data files.

Structured Types
A Structure type comprises a set number of fields that can be of different types. Visual DataFlex supports the Structure type primarily for passing data to and from the Windows API. Refer to Chapter 13 - Advanced Data Types on page 115 for more information on the DataFlex Structure type.

Automatic Type Conversion


Visual DataFlex supports automatic type conversion among variables and

20

Visual DataFlex Language Guide


tokens declared as simple types; String, Date, Integer, Number, Real. Examples of DataFlex type conversion are:
Integer iTest Move "123" To iTest

In the above example an integer variable is declared then it is assigned a string token "123". The result is that the integer 123 is stored into the integer variable. However, the following example will generate a runtime error.
Integer iTest Move "XX123" To iTest

The reason for the error is that Visual DataFlex is unable to interpret the string "XX123" as a integer. Further examples of automatic type conversion are:
Number Integer String Date nTest iTest sTest dTest To nTest To iTest // 2001.0 is stored in nTest // 2001 is stored in iTest

Types

Move 2.001e3 Move nTest

Move 01/01/2001 To dTest Move dTest To sTest

// "01

21

Visual DataFlex Language Guide

Chapter 4 - Variables and Constants


Declaring Variables
A variable is an identifier that references some value that can be changed. A variable declaration is the point in your program where you declare a new variable and designate its type. Visual DataFlex supports two distinct types of variables: Simple (unstructured) variables such as Integer, String, Date, Number and Real types; and Structured variables such as File and Structure types. Simple variables are declared using the following syntax:
{type} {identifier}

Variables & Constants

where {type} is one of the simple DataFlex data types (Integer, Number, Real, Date, String, Handle); and {identifier} is the name that you have assigned to the new variable. Note that you cannot use a DataFlex reserved word as a variable name. A DataFlex variable declaration can occur anywhere within a program. However it is good programming practice to declare all global variables near the top of your program and all local variables near the top of their respective Procedure or Function declarations. Examples of variable declarations are:
Integer Number Real String Date iNew nNew rNew sNew dNew // // // // // declares declares declares declares declares a a a a a new new new new new Integer variable called iNew Number variable called nNew Real variable called rNew String variable called sNew Date variable called dNew

Structured variables such as Data Files and Structures are not declared in this way. Refer to Chapter 13 - Advanced Data Types on page 115 for information on declaring Structure variables. Multiple variables of the same type may be named on a single command line using the following syntax:
{type} {identifier1} {identifier2 indentifierN}

Examples of declaring multiple variables on a single command line are:


Integer iNew iOld String sHot sMedium sCold

23

Chapter 4
Each declared variable is initialized to its null state i.e., Integers, Numbers and Reals are initialized to 0 (zero); Strings are initialized to "" (the null string) and Dates to 01/01/2000. Your program cannot use any variable until the line of code that contains its declaration is executed.

Local Variables
Variables declared within a Procedure or Function are called Local variables. A local variables scope is only inside the Procedure or Function in which it is declared. A variable declaration is deemed to be within a Procedure or Function if the declaration occurs between a Procedure .. End_Procedure or Function .. End_Function command pair. Examples:
Procedure DoNothing Integer iNew String sTest // code exists here that uses the local variables End_Procedure // Code outside the procedure cannot access the local variables

Variables & Constants

The point of local variables is that they cannot be accessed or changed outside of the procedure or function in which they are declared. This means that they can be used inside the procedure with the assurance that no code outside the procedure can corrupt its value.

Global Variables
Variables declared outside procedures and functions are called Global variables. A global variables scope covers the entire program from the point at which it is declared. The disadvantage of global variables is that the programmer has to carefully control their use within a large program to ensure that their value will not change unexpectedly before they are used. Using a global variable within a procedure or function ruins the functions portability. For example, you cannot copy the procedure or function into another program without also copying the variable declaration (at some other point in the program), you must also simulate the initial setting of the global variable in your new program.

24

Visual DataFlex Language Guide


Visual DataFlex variable naming convention suggests that you prefix all of your global variables with a "g". This will help you to easily identify global variables within your program. Example:
Integer giCount String gsCommandLine

Setting the Maximum Length of a Global String In Visual DataFlex global strings have a default length of 80 characters. This can be increased to an absolute maximum of 255 characters when the variable is first declared. The syntax for defining a long global string is:
String {variable-name} {maximum-length}

Variables & Constants

where {variable-name} is the name of the global string variable that is being declared; and {maximum-length} is the maximum number of characters that the global string can contain. The maximum length must be between 1-255. Example:
String gsCommandLine 255

Note: Local string variables have a default maximum length of 16K characters. This length can be increased by using the Set_Argument_Size command.

Data Files
A data file is declared within your DataFlex application using the Declare_DataFile command. The syntax of the Declare_DataFile command is:
Declare_DataFile {filename}

where {filename} is the name of the data file that you are declaring. The DataFlex Open command declares a data file then opens it in preparation for input/output operations. Since you would normally need to open any data file before you use it, this command can be used as a substitute for Declare_DataFile. Example:
Declare_DataFile Customer // Declares a customer data file

25

Chapter 4
Open Inventory opens it // Declares an inventory file and

Note: Before you can declare and use a data file within your program it has to be created. Refer to the Database Builder On-line help for information about creating data files.

Structure Variables
Refer to Chapter 13 - Advanced Data Types on page 115 for information on declaring Structure variables.

Variables & Constants

Declaring Constants
The declaration of a constant corresponds to the declaration of a read-only variable. Constants can be used exactly like variables, except that they cannot be modified. Constants are declared using the following syntax:
Define {Identifier} for {Token}

where {Identifier} is the name assigned to the new constant and {Token} is the token that the named constant will represent. You cannot use a DataFlex reserved word to name a constant. The token that you use can be any Integer, Number, Real, String or Date token. Examples:
Define Define Define C_PI for 3.14156 C_MaxLines for 100 C_CompanyName for "Data Access Corporation"

Visual DataFlex naming convention suggests that you prefix your constant names with a "C_". This will help you to distinguish constants from variable names within your program.

Enumerated Constants
Visual DataFlex provides the Enum_List command for declaring a sequence of integer constants of increasing value. Enumerated constants are declared using the following syntax:
enum_list

26

Visual DataFlex Language Guide


define {Identifier} define {Identifier} define {Identifier} end_enum_list

where {Identifier} is the name assigned to the new integer constant. By default, the first identifier will be assigned the integer constant 0, the second 1, then 2 and so on. Example:
enum_list define C_NoError define C_MinorError define C_Error define C_CriticalError end_enum_list // // // // this symbol = 0 = 1 = 2 = 3

Variables & Constants

You can skip a number in the default sequence by introducing a for clause in the define. For example:
enum_list define C_NoError define C_SysError1 define C_SysError2 define C_SysError3 end_enum_list // // // // = = = = 0 1000 1001 1002

for 1000

27

Visual DataFlex Language Guide

Chapter 5 - Expressions
Expressions are made up of operators and operands. Most DataFlex operators are binary; they take two operands. The rest are unary and take only one operand. Binary operators are placed between the two operands; for example (X + Y). A unary operator always precedes its operand; for example (X).

Expression Syntax

Expressions

Expression Body Values Expressions are written by enclosing an expression body inside parentheses (). The following table lists the valid expression body values:

EXPRESSION BODY
Operand Unary operator followed by an operand Binary operator between two operands Operands An operand can be any of the following items:

EXAMPLE
X. X. X / Y.

OPERAND
Number String Date Constant Variable Function call Expression Body Expression

EXAMPLE
100 "Hello" 01/01/2000 C_Maximum iCount Length("Hello") X+Y (X + Y)

29

Chapter 5
Operators Operators are categorized into several groups depending upon the type of expression. The table below lists all the possible operators:

BINARY ARITHMETIC OPERATORS


+ * /

OPERATION
Addition Subtraction Multiplication Division Power of Maximum Minimum

Expressions

^ Max Min

UNARY ARITHMETIC OPERATOR


-

OPERATION
Sign negation

RELATIONAL OPERATORS
= <> < > <= >= Contains Matches

OPERATION
Equal Not equal Less than Greater than Less than or equal to Greater than or equal to Member of String compare with wildcards

BOOLEAN OPERATORS
Not And Or

OPERATION
negation logical and logical or

30

Visual DataFlex Language Guide STRING OPERATORS


+ *

OPERATION
Concatenation Trim spaces and concatenate Concatenate with a single space

BITWISE OPERATORS
Iand Ior

OPERATION
Bitwise and Bitwise or

Expresssions

Examples
Here are some examples of expressions:
((iTime < 12) and not((sDay = "Sat") or (sDay = "Sun")))

This is a Boolean expression that would return True if the variables iTime and sDay were set to a weekday before 12pm.
(sLastName + , + sFirstName + + sInitial)

This is a string expression that concatenates two string variables with some string constants.

Boolean Expressions
Boolean expressions are evaluated to a result of True or False. In Visual DataFlex any non-zero integer value can represent the Boolean value of True. The integer 0 represents the Boolean value of False.
True <> 0 False = 0

Expressions are evaluated left to right. Visual DataFlex performs short circuit evaluation of Boolean expressions. This means that if the outcome of the entire Boolean expression can be determined by only evaluating part of it then the outcome is returned without evaluating the rest of the expression. This can occur with Boolean and and or operators as demonstrated in the following examples:
((iValueX = 1) or (iValueY = 2))

31

Chapter 5
((iValueX = 1) and (iValueY = 2))

In the first example if (iValueX = 1) is true then (iValueY = 2) is not evaluated because regardless of the outcome the entire expression will still evaluate to true. The same is true for the second example if (iValueX = 1) is False. You most need to be aware of short circuit evaluation when your expression contains a function call as in the following example:
If ((iValueX = 1) or (GetNextCharacter() = 'X')) Begin

Expressions

In this example the function GetNextCharacter is never executed if (iValueX = 1) is True. If it is important that the GetNextCharacter function is executed then you should re-write the expression in the following way:
Move (GetNextCharacter()) To sCharacter If ((iValueX = 1) or (sCharacter = 'X')) Begin

Rules of Operator Precedence


Special Note: DataFlex expressions do not follow any rules of precedence among operators. You must use parentheses to force precedence. For example:
(1 + 2 * 4)

Should be written:
(1 + (2 * 4))

If you want the 2 * 4 part to be evaluated before adding one. DataFlex would evaluate the first example as 12 and the second as 9.

Typecasting of Expressions
Expressions have data types the same as variables. Expressions are automatically typecast according to the highest-order data type represented among the components of the expression. Expression Typecasting, Highest to Lowest Order The following table lists the expression types from highest to lowest order: Real Date

32

Visual DataFlex Language Guide


Number Integer String Boolean Therefore, if an expression contains both Number and Integer components, the value of the expression will be Number. For example:
(5.0 / 2)

This expression will return the Number value 2.5 because one of the components (5.0) is written as number. However:
(5 / 2)

Expresssions

This expression will return the Integer 2 because both components are written as integers. A more explicit way to return a Number answer of 2.5 would be:
(Number(5) / 2)

In this example we are explicitly typecasting the 5 component using the Number function. However, the next example will still yield an answer of 2.0:
(Number(5 / 2))

The reason is that the sub-expression (5 / 2) is evaluated to an Integer result of 2 before the Number function is applied.

33

Visual DataFlex Language Guide

Chapter 6 - Statements
Statements describe the actions that can be executed as part of a programs algorithm.

Simple Statements
A simple statement is a statement that doesnt contain any other statements. Each line of code in your program can contain only one simple statement. The end of line denotes the end of the statement.

Statements

Assignment Statements
Assignment statements are used to change the value of a variable. The syntax of an assignment statement is:
Move {expression} To {Variable}

Some examples of assignment statements are:


Move Move Move Move Move ("Harry") (iX + iY) (iX > 100) (tan(.70711)) (sName) To To To To To sName iTotal bFinished nTangent Customer.Name

If the {expression} part of the assignment statement is a single constant or a variable then you may omit the parentheses (). For example, the first and last assignment statements in the previous example could be re-written:
Move "Harry" Move sName To sName To Customer.Name

Note: Visual DataFlex supports additional specialized assignment commands (Increment, Decrement, Add, and Subtract). Refer to the Language Reference On-line help for more information about these commands.

Continuing a Statement on the Next Line


The end of the line character generally marks the end of the simple statement, however long statements can be continued on the following line by placing a semi-colon (;) character at the end of the first line.

35

Chapter 6
You can continue a statement in this way over several contiguous lines until the maximum line length limitation is reached. Examples of a simple statement continued over more than one line are:
Function TagName string sDrive string sDir returns string string sExt ;

If (sTagname="") ; Get TagName "c:" sDfltDir sDfltExt Else ; Move "" to sTagName

to sTagName

Statements

Move ("This is quite a long message " + ; "so I will break it up over " + ; "three lines!") To sMessage

Note: You cannot break any single token over two lines e.g. in the above example the message could not have been expressed as a single string and broken over several lines. Instead it was written as three strings that are appended together by the append string operator (+).

Compound Statements
A Begin .. End Block is used to mark the beginning and end of a compound statement. A compound statement is a sequence of statements that are to be executed in the same sequence that they are written. The syntax of a compound statement is:
Begin {statement 1} {statement 2} {statement n} End

where {statement} can be any valid DataFlex statement, including another Block. A compound statement can be considered as one single statement comprised of many parts. This is useful when the syntax of some other statement conditionally executes one secondary statement. If you need to execute more than one statement you can use Begin .. End to create a single compound statement.

36

Visual DataFlex Language Guide


Example:
Begin Move (0) To iStart Move (100) To iEnd Move (2) To iStep End

Conditional Statements
A conditional statement selects some other statement for execution depending upon the outcome of one or more Boolean expressions. Refer to Boolean Expressions on page 31 for more information.

Statements

If
The syntax for an if statement is:
If {Boolean-expression} Else {false-statement} {true-statement}

where {Boolean-expression} is some expression that will return a True or False value; {true-statement} is the statement that will execute if True is returned by the Boolean expression; {false-statement} is the statement that will execute if False is returned by the Boolean expression. The else part of the if statement is optional. If it is not present, then execution will continue at the next statement in the program when the Boolean expression is False (without executing the {true-statement}). Some examples of if statements are:
If (iCount > 10) Move ("greater than 10") To sMessage Else Move ("less or equal to 10") To sMessage

If ((iValue 1) < 1000) Begin Move (iValue) To Sales.Small Move ("sub 1000") To Sales.Note End Else Begin Move (iValue) To Sales.Large Move ("over 1000") To Sales.Note End

37

Chapter 6
If (bSmoking) Move ("Somebody stop me!") To sMessage

Case
The syntax for a Case statement is:
Case Begin Case {Boolean-expression1} {statement1} Case Break Case {Boolean-expression2} {statement2} Case Break Case {Boolean-expression3} {statement3} Case Break Case Else {else-statement} Case End

Statements

If Boolean-expression1 is True then statement1 is executed, if Booleanexpression2 is True then statement2 is executed and if Boolean-expression3 is True then statement3 is executed. If none of the Boolean-expressions are true then the else-statement is executed. The Case statement will allow any number of Boolean-expressions and statements to be executed. The Case Else and {else-statement} are optional. If it is not present then execution will continue at the next statement in the program when all the Boolean expressions are False. It is normal to end each Case with a Case Break command. The Case Break command will immediately halt execution of the Case statement and program execution will continue at the next statement in the program (following the Case statement). If you do not end each Case with a Case Break then execution will continue down through all the Cases until a Case Break is executed or the Case statement ends. An example of a Case statement is:
Case Begin Case (sAnimal = "Cat") Move ("Meow") To sNoise Case Break Case (sAnimal = "Dog") Move ("Arf") To sNoise Case Break

38

Visual DataFlex Language Guide


Case (sAnimal = "Bird") Move ("Tweet") To sNoise Case Break Case Else Move ("") To sNoise Case End

Looping Statements
Looping statements specify certain statements to be executed repeatedly.

While
A While statement contains a Boolean expression that controls the repeated execution of a list of statements. The list of statements is terminated by a Loop command. The syntax of a While statement is:
While {Boolean-expression} {statement 1} {statement 2} {statement n} Loop

Statements

The Boolean expression controlling the repetition is evaluated before the statements are executed. The contained statements are executed as long as the expression is True. If the expression is False at the beginning then, the statements are not executed at all. An example of a While statement is:
// initialize the variables Move "" To sName Move "" To sList // Loop until Fred's name is entered While ((sName) <> "Fred") Move (GetNextName()) To sName // retrieve the next name Move (sList + ";" + sName) To sList Loop

Repeat
A Repeat statement contains a Boolean expression that controls the repeated

39

Chapter 6
execution of a list of statements. The list of statements begins with the Repeat command and is terminated by an Until command. The syntax of a Repeat statement is:
Repeat {statement 1} {statement 2} {statement n} Until {Boolean-expression}

Statements

The Boolean expression controlling the repetition is evaluated after the statements are executed. The contained statements are executed as long as the expression is True. If the expression is False at the beginning then the statements are executed only once. An example of a Repeat statement is:
Move 1 To iPos

Repeat Move (Mid(sMessage,1,iPos)) To sChar Move (iPos + 1) To iPos Until ((sChar = "Z") or (iPos > (Length(sMessage))))

For
The For statement is used to repeatedly execute a statement a fixed number of times. The number of repetitions is controlled by a variable that is incremented by one for each repetition until it matches the final-value. The syntax of a For statement is:
For {control-variable} From {initial-value} To {final-value} {statement 1} {statement 2} {statement n} Loop

where {control-variable} is the integer variable that is used to control the number of repetitions; {initial-value} is the initial setting for the control variable the first time the For statement is executed. The initial value can be a constant, variable, or expression of type Integer; {final-value} is the highest value that the control-variable will be incremented to during execution of the For statement. When the control variable exceeds the final value then the For

40

Visual DataFlex Language Guide


statement will stop looping. The final value can be a constant, variable, or expression of type Integer. The statements contained by the For statement are executed once for every incremental value of the control variable in the range initial value to final value. The Loop command marks the end of the block of statements that are contained by the For statement. Here are some examples for statements:
For iCount From 1 To 255 Move (sACSIIchars + Character(iCount)) To sASCIIchars Loop

Statements

For iX From ixStart To ixStop For iY From iyStart To iyStop Move (GraphValue(iX, iY)) To iValue Showln "Value at " iX "," iY " = " iValue Loop Loop

41

Visual DataFlex Language Guide

Chapter 7 - Procedures and Functions


An important part of the Visual DataFlex language is the concept of a routine. A routine is a named block of code comprising multiple statements that is designed to perform some operation. Each routine that you define can be invoked multiple times throughout your program to perform its designated operation. A DataFlex routine can assume two forms: a Procedure or a Function. The main difference between the two constructs is that a function has a return value, while a procedure does not. Procedures and Functions can be passed data as parameters each time they are invoked. They can also declare local variables.

Procedure & Functions

Procedures
Declaring Procedures
A procedure declaration associates an identifier with a block of code as a procedure. That procedure can then be called within your program by a Send statement. The syntax for a procedure declaration is:
Procedure {procedure-name} Global [{type1} {param1} {type2} {param2} ] [{variable-declarations}] {statement 1} {statement 2} {statement n} End_Procedure

where {procedure-name} is the identifier associated with the procedure. You cannot use a DataFlex reserved word as a procedure name. {type1} is the data type of parameter {param1}, {type2} is the data type of {param2} etc; {variable-declarations} are the local variables that you can declare for the procedure and {statement 1-n} are the statements that are executed whenever the procedure is called. You can define zero or more parameters for each procedure. Each parameter behaves like a local variable that is initialized by the statement that calls the procedure. The data types of each parameter can be any DataFlex simple

43

Chapter 7
type (Integer, Number, Real, Boolean, Date, String, Pointer, handle or Dword). Here is an example of a procedure declaration:
Procedure DoShowCharacters Global String sMessage // this procedure takes the string sMessage and outputs // each character separately with intervening commas. Integer iPos Integer iLength Move (Length(sMessage)) To iLength For iPos From 1 To (iLength - 1) Show (Mid(sMessage, 1, iPos)) "," Loop Showln (Mid(sMessage, 1, iLength)) End_Procedure

Procedure & Functions

Calling Procedures
Once a procedure has been declared you can execute it in your program with a Send statement. The syntax of the Send statement is:
Send {procedure-name} [{param1} {param2} {paramN}]

where {procedure-name} is the name of the previously declared procedure that you are executing; {param1 .. N} are the parameters that you are passing to the called procedure. The number and order of parameters that you pass must match the list of parameters in the procedures declaration. The parameters you pass can be constants, variables or expressions, so long as they are of comparable type to the matching parameter in the procedure declaration. Examples of calling a procedure are:
Send DoWriteCharacters "Some Character String" Send DoWritePaddedString ("Message = " + sMessage) sPadCharacter

Functions
Declaring Functions
A function declaration associates an identifier with a block of code as a function. That function can then be called in you program within an

44

Visual DataFlex Language Guide


expression. The syntax for a function declaration is:
Function {function-name} Global [{type1} {param1} {type2} {param2} ] ; Returns {return-type} [{variable-declarations}] {statement 1} {statement 2} {statement n} Function_Return {return-value} End_Function

where {function-name} is the identifier associated with the function. You cannot use a DataFlex reserved word as a function name; {type1} is the data type of parameter {param1}, {type2} is the data type of {param2} etc; {returntype} is the declared type of the function. The value that is returned by the function will be compatible with this type. {variable-declarations} are the local variables that you can declare for the function; {statement 1-n} are the statements that are executed whenever the function is called and {returnvalue} is the value returned by the function. You can define zero or more parameters for each function. Each parameter behaves like a local variable that is initialized by the statement that calls the function. The data types of each parameter and the return value can be any DataFlex simple type (Integer, Number, Real, Boolean, Date, String, Pointer, handle or Dword). Each function must return a value. Execution of the function stops immediately after a Function_Return statement has been executed. Here is an example of a function declaration:
Function PowerOf Global Integer Integer iReturnVal Integer iCount Move 1 To iReturnVal For iCount From 1 To iY Move (iX * iReturnVal) To iReturnVal Loop Function_Return iReturnVal End_Function Integer iX Integer iY Returns

Procedure & Functions

45

Chapter 7 Calling Functions


Once a function has been declared you can execute it in your program within an expression. The syntax for calling a function in an expression is:
({function-name}([{param1}, {param2}, {paramN}]))

where {function-name} is the name of the previously declared function that you are executing; {param1 .. N} are the parameters that you are passing to the called function. The number and order of parameters that you pass must match the list of parameters in the functions declaration. The parameters you pass can be constants, variables or expressions, so long as they are of comparable type to the matching parameter in the function declaration.

Procedure & Functions

Examples of calling a function are:


If (CurrentUser() = "ADMIN") Showln "Administrator" Move (PowerOf(2,8)) To iAnswer Move (FormatString(sMyString)) To sMyString

Forward Declarations
Procedures and Functions can be forward declared using the Register_Procedure and Register_Function statements respectively. Forward declaring allows you to reference the procedure or function in some other piece of code before it is formally declared. The compiler would generate an error if you tried to do this without a forward declaration. The syntax of the Register_Procedure and Register_Function statements are:
Register_Procedure {procedure-name} Global [{type1} {param1} ; {type2} {param2} ] Register_Function {function-name} Global [{type1} {param1} ; {type2} {param2} ] ; Returns {return-type}

In other words, the syntax for forward declaring a procedure or function is the same as the first line of a regular procedure or function declaration except that the commands Register_Procedure and Register_Function are used instead. The type, number and order of parameters in the forward declaration must match the real procedure or function declaration. Examples of forward procedure and function declarations are:
Register_Procedure Register_Function Global Global DoWriteCharacters String sMessage Powerof Integer iX Integer iY ; Returns Integer

46

Visual DataFlex Language Guide


The above example would allow you to reference the registered procedure or function inside the body of some other procedure or function even though its formal declaration has not yet been made.

Design Considerations
As their declaration suggests, Procedures and Functions are global; i.e., they can be called anywhere within the program. In a carefully designed object-oriented program there is very little need to declare and use global procedures since each class should declare its own set of methods to perform all necessary operations.

Procedure & Functions

Global functions are more useful since they could be viewed as an extension to Visual DataFlexs built-in function library. However, it should be remembered that any new global procedure or function you write that is used by a class will break that classs encapsulation. One consequence of breaking encapsulation is to make it more complicated to reuse the class in other programs (a key benefit of object-oriented programming). The reason this occurs is that the class definition now contains an outside dependency upon any global functions that it uses. Its use is therefore dependant upon the existence of these functions.

DataFlex built-in Function Library


Visual DataFlex contains a useful library of built-in global functions for performing a variety of programming operations. The following is a brief listing of all the functions grouped by the general category of operation that they perform.

Math Functions FUNCTION


abs acos asin atan

RETURNS
The absolute value of a passed value. The arc cosine of a passed value. The arc sine of a passed value. The arc tangent of a passed value.

47

Chapter 7 FUNCTION
cos exp log mod random round

RETURNS
The cosine of a passed value. The antilogarithm of a passed value. The logarithm of a passed value. The remainder of the integer division of two passed values. A random number. An integer value from a decimal value by rounding the decimal portion. The sine of a passed value. The square root of a passed value. The tangent of a passed value.

Procedure & Functions

sin sqrt tan

String Functions FUNCTION


append ascii center

RETURNS
The concatenation of two strings. The ASCII value of a character. A string of specified length with spaces added to, or characters truncated from, both sides so that the content is centered. The character corresponding to a specified ASCII number. Calls an evaluation engine to evaluate an expression that is passed as a string. The result of this evaluation is returned. A string made up of one string inserted into another at a specified point. The leftmost characters of a passed string up to a specified length. The length of a string. The passed string with all letters converted to lower case.

character eval

insert left length lowercase

48

Visual DataFlex Language Guide FUNCTION


ltrim mid overstrike

RETURNS
The passed string with all leading spaces removed. A substring derived from the passed value starting at a specified position and of specified length. A string whose value contains a passed substring at a specified location. The substring will overwrite any characters in the original string at the specified location. A string of specified length with spaces added to, or truncated from, the right of a passes string. The position of the first occurrence of one passed string within another. A string consisting of the passed string with a specified number of characters removed at a specified location in the string. A string made up of a specified number of repetitions of the passed string. A string with the first occurrence of one passed substring replaced with another. A string with all occurrences of one passed substring replaced with another. The rightmost characters of a passed string up to a specified length. The passed string with all trailing spaces removed. The passed string with all leading and trailing spaces removed. The passed string with all letters converted to upper case.

pad pos remove

Procedure & Functions

repeat replace replaces right rtrim trim uppercase

Time and Date Functions FUNCTION


Date CurrentDateTime

RETURNS
Returns the passed value as a date. Returns a DateTime variable or Time variable that

49

Chapter 7 FUNCTION
DateGetDay DateGetDayOfWeek DateGetDayOfYear DateGetHour

RETURNS
contains the current local time. Returns the day of the month component of the given DateTime variable dtVar. Returns the day of the week of the given DateTime variable. Returns the day of the year of the given DateTime variable. Returns the hour component of the given DateTime variable. Returns the Minute component of the given DateTime variable. Returns the Month component of the given DateTime variable. Returns the Second component of the given DateTime variable. The DateGetYear function returns the Year component of the given DateTime variable. Returns a new DateTime value equal to the passed DateTime with its day adjusted to the passed Day value. Returns a new DateTime value equal to the passed DateTime with its hour adjusted to the passed Hour value. Returns a new DateTime value equal to the passed DateTime with its minute adjusted to the passed Minute value. Returns a new DateTime value equal to the passed DateTime with its month adjusted to the passed Month value. Returns a new DateTime value equal to the passed DateTime with its seconds adjusted to the passed Seconds value. Returns a new DateTime value equal to the passed DateTime with its year adjusted to the passed Year

Procedure & Functions

DateGetMinute DateGetMonth DateGetSecond DateGetYear DateSetDay

DateSetHour

DateSetMinute

DateSetMonth

DateSetSecond

DateSetYear

50

Visual DataFlex Language Guide FUNCTION


IsDateValid SpanDays SpanHours SpanMinutes SpanSeconds SpanTotalDays

RETURNS
value. Returns a Boolean value of 0 if the date is invalid, or 1 if the date is a valid date. Returns the Days component of the given TimeSpan variable. Returns the Hours component of the given TimeSpan variable. Returns the Minutes component of the given TimeSpan variable. The SpanSeconds function returns the Seconds component of the given TimeSpan variable. Calculates the total number of days in the time span and returns a double precision real number of that amount. Calculates the total number of Hours in the time span and returns a double precision real number of that amount. Calculates the total number of Minutes in the time span and returns a double precision real number of that amount. Calculates the total number of Seconds in the time span and returns a double precision real number of that amount.

Procedure & Functions

SpanTotalHours

SpanTotalMinutes

SpanTotalSeconds

Type Coercion Functions FUNCTION


Cast Convert date integer number

RETURNS
Returns a variable of the specified type that is the best conversion from the original variable. Returns a variable of the specified type that is the best conversion from the original variable. The passed value as a date. The passed value as an integer. The passed value as a number type.

51

Chapter 7 FUNCTION
real string

RETURNS
The passed value as a real number. The passed value as a string.

Miscellaneous Functions FUNCTION


AddressOf hi if low

RETURNS
Returns the address of an argument. The upper 2-bytes (16-bits) of a 4-byte integer. One of two passed values depending on the outcome of a binary expression. The lower 2-bytes (16-bits) of a 4-byte integer.

Procedure & Functions

Examples calling DataFlex built-in functions are:


Sysdate sDate Move (Right(sDate, 4)) To sYear // get todays date // extract the year

// replace all occurrences of bad in the variable // sMyString with good. Move (Replaces(sMyString, bad, good)) To sMyString Move (Tan(nAngle) * nDistance)) To nHeight

Refer to the Language Reference On-line help for detailed information on each built-in function.

52

Visual DataFlex Language Guide

Chapter 8 - Classes
A class is a structured type consisting of a fixed number of components. The possible components are methods, properties and private-objects. Class components are sometimes also referred to as members.

Class Declaration
A class is declared using a Class Declaration statement. The syntax of the class declaration statement is:
Class {class-name} is a {superclass}

Classes

[ Procedure Construct_Object Forward Send Construct_Object {property-declarations} {private-objects} End_Procedure ] [{method-declarations}] End_Class

where {class-name} is the name of the new class and {superclass} is the name of an existing class that the new class is derived from. Each class inherits all components of its superclass. Each inherited method may be augmented, overridden or canceled inside the new class declaration. You may define new properties, methods and private objects inside the class constructor method (this is fully explained in the following sections). The end of the class declaration block is marked by the End_Class command. Visual DataFlex provides a library of high-level classes that are designed to perform most of the functionality you need for building database applications. You can use these built-in classes as the foundation of your own extended class library from which you would construct your applications. The Class Reference manual contains a complete listing of every class in the Class Library. An example of a simple class declaration is:
Class cOK_Button End_Class is a Button

53

Chapter 8

This example declares a new class called cOK_Button that is based on the built-in Button class. This new class will perform exactly as its superclass (Button). Since there are no new properties, methods or private objects there would be no new behavior associated with the new class. Visual DataFlex naming convention suggests that you prefix your new class names with a "c". This will help you ensure that no naming conflict will occur between your class and other identifiers in your program.

Properties

Classes

A property definition declares a named data element of the class. Together the class properties define the attributes of each instance of a class. Properties are not variables. Examples of properties are the caption of a panel, the location of a checkbox, the main file of a data dictionary, etc.

Declaring Properties
The syntax for declaring a new property is:
Property {property-type} {property-name} {initial-value}

where {property-type} is the data type for the new property. This can be one of: Integer, Number, Real, Date, String, Pointer or Handle; {property-name} is the identifier that you assign to the property. You can not use a DataFlex reserved word as a property identifier; {initial-value} is the default setting for the property for each instance of the class. Class properties must be declared inside the Constructor method of the class. The name of every classs constructor method is Construct_Object. See the sections on Constructors and Destructors for more information. An example of declaring a class with two new properties is:
Class cOK_Button is a Button // Constructor: Procedure Construct_Object Forward Send Construct_Object Property Integer piClickCount Property String psBusyLabel

// very important! 0 "-Busy-"

54

Visual DataFlex Language Guide


End_Procedure End_Class

This example declares a class, cOK_Button, with two new properties, piClickCount and psBusyLabel. Note that the properties are declared inside the class constructor method, Construct_Object. An important part of the Construct_Object method is the "Forward Send Construct_Object" statement. This is the line that ensures that all of the definitions in the superclasss constructor are inherited by the new class. Visual DataFlex property naming convention suggests that you prefix all property names with p followed by a letter that indicates its data type (i, n, r, b, d, s, h). Refer to Appendix B - Naming Conventions on page 129 for more information.

Classes

Setting Property Values


Object properties are set by executing a DataFlex Set statement. The syntax of the set statement is:
Set {property-name} [of {object-ID}] To {value}

where {property-name} is the name of the property that is being set; {objectID} is a handle to the object whose property is being set and {value} is the new value of the property. The value can be any constant, variable or expression that is of a compatible type to the property. If you are setting a property of the current object (current instance of the class) then you can use the Self keyword as the object-id. See the section on the Self Word below for more details. Alternatively you can omit the object-id clause completely and Visual DataFlex will automatically reference the current object. Here is an example of a class declaration that sets properties of the current object:
Class cOK_Button is a Button // Constructor: Procedure Construct_Object Forward Send Construct_Object Property Integer piClickCount Property String psBusyLabel

// very important! 0 ""

Set Label To "OK" // same as writing Set Label of Self To "OK"

55

Chapter 8
Set Help_ID To C_OkButtonHelp Set Status_Help To "Click OK to begin operation" Set psBusyLabel To "-Busy-" End_Procedure End_Class

The above example sets four properties: Label, Help_ID and Status_Help are properties that were inherited from the superclass; psBusyLabel is a new property. A property must be declared before you can set it. In the above example, all the property settings occur in the constructor method. However, you can set properties of the current object inside any method that is part of the class definition.

Classes

If you are setting a property of some other object then you need to provide a handle to that object in the {object-ID} part of the Set statement. The DataFlex Handle type can be used to create variables or properties for storing object handles. Examples of set statements that set properties of some external object are:
Set Checked_State of Set Minimum_Position of Set Maximum_Position of oMarried_Checkbox oSpinForm To 0 oSpinForm To 100 To True

In the above examples, oMarried_Checkbox is the name of an instance of the Checkbox class and oSpinform is an instance of the SpinForm class. Both these classes are built into the Visual DataFlex class library. Note: You cannot use the Move statement to set a property value. The Move statement is only for assigning values to variables.

Reading Property Values


Object properties are read by executing a DataFlex Get statement. The syntax of the get statement is:
Get {property-name} [of {object-ID}] To {variable-id}

where {property-name} is the name of the property that is being read; {objectID} is a handle to the object whose property is being read and {variable-id} is the name of a variable that will receive the propertys value. The receiving variable can be any variable that is of a compatible type to the property. If you are reading a property of the current object (current instance of the class) then you can use the Self keyword as the object-id. See the section on The Self Keyword below for more details. Alternatively you can omit the

56

Visual DataFlex Language Guide


object-id clause completely and DataFlex will automatically reference the current object. Here is an example of a class declaration that reads properties of the current object:
Class cCount_Button // Constructor: is a Button

Procedure Construct_Object Forward Send Construct_Object Property Integer piClickCount End_Procedure Procedure OnClick Integer iCount Get piClickCount Move (iCount + 1) Set piClickCount Set Label End_Procedure End_Class

// very important! 0

To To To To

iCount iCount iCount iCount

Classes

The above example declares a class, based on the Button class, with a new property, piClickCount. The button class is designed to execute a method called OnClick each time the button is clicked on by the mouse (this is called an event method). The OnClick method has been defined to read the piClickCount property into a variable, increment it, set the property back to its incremented value and also display the value in the buttons label (by setting the label property). If you are reading a property of some other object then you need to provide a handle to that object in the {object-ID} part of the Get statement. The DataFlex Handle type can be used to create variables or properties for storing object handles. Examples of get statements that read properties of some external object are:
Get Checked_State of Get Minimum_Position of Get Maximum_Position of oMarried_Checkbox To bChecked oSpinForm To iMax oSpinForm To iMin

In the above examples, oMarried_Checkbox is an instance of the Checkbox class and oSpinform is an instance of the SpinForm class. Both these classes are built into the Visual DataFlex class library.

57

Chapter 8 Forward Declaring Properties


Properties can be forward declared using the Register_Procedure and Register_Function statements. Forward declaring allows you to reference a property in some method before it is formally declared. The compiler would generate an error if you tried to do this without a forward declaration. The syntax for forward declaring a property is:
Register_Procedure {property-name} Set {type} {param} Register_Function {property-name} Returns {type}

where {property-name} is the name of the property that you are forward declaring; {type} is the data type of the property; and {param} and be any variable identifier ({param} is not used).

Classes

The Register_Procedure part of the forward declaration is needed when you are forward referencing a property in a Set statement and the Register_Function part of the forward declaration is needed when you are forward referencing a property in a Set statement. If you only have one type of forward reference then you can omit the unused part of the forward declaration. Examples of forward declaring properties follows:
Register_Procedure Set Register_Function Register_Procedure Set Register_Function Height Height Width Width Integer iX Returns Integer Integer iY Returns Integer

The above example would allow you to reference the registered properties inside the body of some method declaration even though the properties own formal declaration have not yet been made.

Methods
A method is a procedure or function that is declared inside the Class definition statement and performs an operation, typically on an instance of the class. Visual DataFlex supports three different kinds of methods. Procedure Procedure Set Function

58

Visual DataFlex Language Guide


Procedures perform discrete operations on the object or on behalf of the object. Procedure Set methods perform discrete operations then set some state, or attribute, of the object. Functions perform a discrete operation then return some state, or attribute, of the object. Note: Class methods are not like the Global Procedures and Functions that are described in the Chapter 7 - Procedures and Functions chapter. Global procedures and functions are declared and called differently and are intended for a different purpose than class methods.

Declaring Procedure Methods


A Procedure method performs a discrete operation on the object or on behalf of the object. The syntax for declaring a Procedure Method is:
Procedure {method-name} [{type1} {param1} {type2} {param2} ] [{variable-declarations}] {statement 1} {statement 2} {statement n} End_Procedure

Classes

where {method-name} is the name of the procedure method. You cannot use a DataFlex reserved word as a method name. {type1} is the data type of parameter {param1}, {type2} is the data type of {param2} etc; {variabledeclarations} are the local variables that you can declare for the method and {statement 1-n} are the statements that are executed whenever the method is called. You can define zero or more parameters for each procedure method. Each parameter behaves like a local variable that is initialized by the statement that executes the method. The data types of each parameter can be any DataFlex simple type (Integer, Number, Real, Boolean, Date, String, Pointer, Handle or Dword). Here is an example of a class definition with a three procedure method declarations:
Class cCount_Button // Constructor: is a Button

Procedure Construct_Object Forward Send Construct_Object

// very important!

59

Chapter 8
Property Integer piClickCount End_Procedure Procedure DoPrint String sMessage Showln "Our message today is:" Showln sMessage Showln End_Procedure Procedure OnClick Integer iCount Get piClickCount To Move (iCount + 1) To Set piClickCount To Send DoPrint ("Click End_Procedure End_Class 0

iCount iCount iCount count = " + String(iCount))

Classes

The three methods in this example are: Construct_Object, the class constructor; DoPrint, a procedure that outputs a message that is passed to it as a parameter; and OnClick. The Button class is designed to execute a method called OnClick each time the button is clicked on by the mouse. The OnClick method we have defined will increment a property then execute the DoPrint method to print the value of that property. A Procedure method executes until it reaches an End_Procedure or it encounters a Procedure_Return command. Procedure_Return can be used to halt execution of a Procedure method at any point in the procedure body. For the OnClick method in the previous example could be re-written as follows:
Procedure OnClick Integer iCount Get piClickCount To iCount If (iCount >= 1000) Begin Error 300 "You have tried to too many times. Give up!" Procedure_Return End Move (iCount + 1) To iCount Set piClickCount To iCount Send DoPrint ("Click count = " + String(iCount)) End_Procedure

DataFlex also supports method overloading. Refer to the section on Method Overloading for information on declaring overloaded Procedure Methods.

60

Visual DataFlex Language Guide Declaring Procedure Set Methods


A Procedure Set method performs a discrete operation, then sets some state, or attribute, of the object. Procedure Set mimics the setting of a property. The syntax for declaring a Procedure Set Method is:
Procedure Set {method-name} [{type1} {param1} {type2} {param2} ] [{variable-declarations}] {statement 1} {statement 2} {statement n} End_Procedure

where {method-name} is the name of the Procedure Set method. You cannot use a DataFlex reserved word as a method name. {type1} is the data type of parameter {param1}, {type2} is the data type of {param2} etc; {variabledeclarations} are the local variables that you can declare for the method and {statement 1-n} are the statements that are executed whenever the method is called. You can define zero or more parameters for each Procedure Set method. Each parameter behaves like a local variable that is initialized by the statement that executes the method. The data types of each parameter can be any DataFlex simple type (Integer, Number, Real, Boolean, Date, String, Pointer, Handle or Dword). Here is an example of a class definition that declares a Procedure Set method:
Class cCount_Button // Constructor: is a Button

Classes

Procedure Construct_Object Forward Send Construct_Object // very important! Property Integer Private_piClickCount 0 End_Procedure Procedure Set piClickCount Integer iValue Set Private_piClickCount To iValue Set Label To iValue End_Procedure Function piClickCount Returns Integer Local Integer iValue Get Private_piClickCount To iValue

61

Chapter 8
Function_Return iValue End_Function Procedure OnClick Integer iCount Get piClickCount Move (iCount + 1) Set piClickCount End_Procedure End_Class

To iCount To iCount To iCount

Classes

The class declaration in the above example is a new Button class that is designed to record how many times it has been clicked and display that number in the buttons label. A Procedure Set method has been defined to take care of setting an internal property that records the number of clicks. This Procedure Set will also perform the task of setting the buttons label. A Function has also been designed to retrieve the value of the internal property. Thus, we have defined a new interface to set and read the number of times that the button has been clicked. The new interface guarantees that each time the piClickCount property is set, the buttons label will also be adjusted. The Button class is designed to execute a method called OnClick each time the button is clicked by the mouse. The OnClick method we have defined reads the piClickCount property to a local variable, increments it, then sets piClickCount to the incremented value. The Get piClickCount statement will execute the piClickCount function method and the Set piClickCount statement executes the piClickCount procedure set method. Thus the declaration of a Procedure Set and a Function method simulate a new class property called piClickCount. DataFlex also supports method overloading. Refer to the section on Method Overloading for information on declaring overloaded Procedure Methods.

Declaring Function Methods


A Function method performs a discrete operation then returns some state, or attribute, of the object. Calling a Function method simulates reading a property. The syntax for declaring a Function Method is:
Function {method-name} [{type1} {param1} {type2} {param2} ] ; Returns {return-type} [{variable-declarations}] {statement 1}

62

Visual DataFlex Language Guide


{statement 2} {statement n} [Function_Return {return-value}] End_Procedure

where {method-name} is the name of the function method. You cannot use a DataFlex reserved word as a method name. {type1} is the data type of parameter {param1}, {type2} is the data type of {param2} etc; {return-type} is the declared type of the function method. The value that is returned by the method will be compatible with this type; {variable-declarations} are the local variables that you can declare for the method and {statement 1-n} are the statements that are executed whenever the method is called and {return-value} is the value returned by the method.

Classes

You can define zero or more parameters for each function method. Each parameter behaves like a local variable that is initialized by the statement that executes the method. The data types of each parameter can be any DataFlex simple type (Integer, Number, Real, Boolean, Date, String, Pointer, Handle or Dword). Each function method must return a value. Execution of the method stops immediately after a Function_Return statement has been executed. See the DataFlex also supports method overloading. Refer to the section on Method Overloading for information on declaring overloaded Procedure Methods. Declaring Procedure Set Methods section above for an example on declaring a function method. DataFlex also supports method overloading. Refer to the section on Method Overloading for information on declaring overloaded Procedure Methods.

Forward Declaring Methods


Methods can be forward declared using the Register_Procedure and Register_Function statements respectively. Forward declaring allows you to reference one procedure or function in some other method before it is formally declared. The compiler would generate an error if you tried to do this without a forward declaration.

63

Chapter 8
Forward Declaring Procedure Methods The syntax for forward declaring a Procedure method is:
Register_Procedure {procedure-name} [{type1} {param1} ; {type2} {param2} ]

Forward Declaring Procedure Set Methods The syntax for forward declaring a Procedure Set method is:
Register_Procedure {procedure-name} Set [{type1} {param1} ; {type2} {param2} ]

Forward Declaring Function Methods The syntax for forward declaring a Function method is:

Classes

Register_Function {function-name}

[{type1} {param1} ; {type2} {param2} ] ; Returns {return-type}

In other words, the syntax for forward declaring a method is the same as the first line of a regular method declaration except that the commands Register_Procedure and Register_Function are used instead. The type, number and order of parameters in the forward declaration must match the real procedure or function declaration. Examples of forward declaring methods follows:
Register_Procedure Register_Procedure Set Register_Procedure Set Register_Function Register_Function DoWriteCharacters String sMessage Height Integer iX Width Integer iY Height Returns Integer Width Returns Integer

The above example would allow you to reference the registered methods inside the body of some other method declaration even though its own formal declaration has not yet been made.

Event Methods
Event methods are a specialized implementation of procedure methods. Each class in the Visual DataFlex class library will execute certain event methods during important operations. For example, the TreeView class supports many Event methods such as: OnCreateTree, (this event is executed when a TreeView object is created); OnItemChanged, (this event is executed

64

Visual DataFlex Language Guide


whenever the focused item in a treeview moves from one item to another), and so on. These event methods are the points at which you can design specialized behavior for the class during important operations. You design the specialized behavior by writing the appropriate event method in your class declaration. You need to study the documentation for each class to determine which event methods are available for augmentation. An example of augmenting a event methods follows:
Class cMyButton is a Button Procedure OnClick Send Info_Box "I have been clicked" End_Procedure End_Class

Classes

In this example we have designed a new button class called cMyButton. The OnClick event has been augmented so that each time the button is clicked a message will be displayed.

Calling Procedure Methods


A procedure method is executed by calling the method. This is sometimes referred to as sending a message. The syntax for calling a procedure method is:
Send {method-name} [of {object-ID}] {param1 paramN}

where {method-name} is the name of the procedure method being executed; {object-ID} is a handle to the object that will receive the instruction to execute the method; {param1..paramN} are the parameters that you are passing to the called method. The order of the parameters must match the list of parameters in the methods declaration. The parameters you pass can be either constants, variables or expressions, so long as they are of comparable type to the matching parameters in the method declaration. If you are calling a method of the current object (current instance of the class) then you can use the self keyword as the object-id. See the section on The Self Keyword below for more details. Alternatively you can omit the object-id clause completely and DataFlex will automatically reference the current object. An example of a calling procedure method follows:

65

Chapter 8
Class cMyEdit is a Edit Procedure DoAddName String sName Get psName To sName Send Append_Text sName // same as writing Send Append_Text End_Procedure Procedure Construct_Object Forward Send Construct_Object Property String psName Public "John" On_Key Key_Alt+Key_D Send DoAddName End_Procedure End_Class

of Self

sName

The above example declares a class cMyEdit based on the Edit class. The Contruct_Object procedure defines an accelerator-key (Alt+N) that will call the DoAddName method. The DoAddName method will read a string property and append it to the end of the text by calling the inherited Append_Text method. If you are calling a method of some other object then you need to provide a handle to that object in the {object-ID} part of the Send statement. The DataFlex Handle type can be used to create variables or properties for storing object handles. Examples of Send statements that call methods of some external object are:
Send Beginning_of_line Send Goto_Line Send Move_Absolute of oEdit of oEdit of oEdit iLineNumber 20 5

Classes

In the above example, oEdit is an instance of the Edit class. Refer to the section on Method Overloading for more information on calling procedure methods.

Calling Procedure Set Methods


A Procedure Set method is executed by using a Set statement. The general syntax of the Set statement is:
Set {method-name} [of {object-ID}] {param1 paramN} To {value1 valueN} ;

where {method-name} is the name of the method that is being executed; {object-ID} is a handle to the object whos method is being executed; {param1

66

Visual DataFlex Language Guide


paramN} and {value1 valueN} are all parameters that are passed to the Procedure Set method. The order of the parameters must match the list of parameters in the method's declaration, this is explained in further detail below. The parameters you pass can be either constants, variables or expressions, so long as they are of comparable type to the matching parameters in the method declaration. If you are calling a Procedure Set method of the current object (current instance of the class) then you can use the Self keyword as the object-id. See the section on The Self Keyword below for more details. Alternatively you can omit the object-id clause completely and DataFlex will automatically reference the current object. Whether you place your parameters as {param1 paramN} or {value1 valueN} is really a matter on convention and will differ depending on the specific Procedure Set method you are executing. However, you must pass at least one parameter as value1. Simple Procedure Set Procedure Set methods are used primarily to simulate setting a Property. These are called simple procedure set methods. The syntax for calling simple procedure set methods is:
Set {method-name} [of {object-ID}] To {value}

Classes

This is exactly the same as the syntax for setting a property value. Here are some examples of calling a simple Procedure Set method.
// Call some Procedure Set methods of the "current" object Set Label To "Customer Name:" // set the label of the current object Set Color To clBtnFace // set the color of the current object // Call some Procedure Set methods of an "external" object Set Label of oAddrForm To "Customer Address:" Set Color of oAddrForm To clGreen

In the above example, oAddrForm is an instance of the Form class. As the above examples show, executing a simple Procedure Set method is indistinguishable from setting a property.

67

Chapter 8
Complex Procedure Set Some Procedure Set methods are used to set two or more values at once. These are called complex procedure set methods. The general syntax for executing a complex procedure set is:
Set {method-name} [of {object-ID}] To {value1 valueN}

Here are some examples of calling complex Procedure Set methods.


Set Location to 10,10 Set Size To 10 10 // set location of the current object

To iHeight iWidth

Classes

// now execute procedure sets of an "external" object Set Location of oAddrForm To 10 10 Set Size of oAddrForm To iHeight iWidth

In the above example, oAddrForm is an instance of the Form class. Note: Complex Procedure Set methods are being phased out of Visual DataFlex in preference for multiple simple procedure set methods or properties. Procedure Set With Special Parameters Some Procedure Set methods require special parameters to be passed. The parameters are usually designed to identify which property the method will set from a list, or array, of similar properties. Common syntax for executing a procedure set with parameters is:
Set {method-name} [of {object-ID}] {item-id} To {value}

where {item-id} denotes the index to an array of properties. {Item-id} should be an integer constant, variable or expression. The DataDictionary class contains a set of properties that require calling procedure set methods with special parameters. The general syntax for calling these procedure set methods is:
Set {method-name} ; Set {method-name} ; [of {object-ID}] To {value} [of {object-ID}] To {value} Field {file.field-id}

File_Field {file.field-id}

68

Visual DataFlex Language Guide


where {file.field-id} is a data file field identifier (see Data File Type). Procedure Set methods that take {file.field-id} parameters exist primarily in the DataFlex DataDictionary class. Here are some examples of calling Procedure Set methods with special parameters:
For iCount From 0 To 9 Set Array_Value iCount Loop To 0

In this example, the Array_Value method is being called to set the indexed property to 0 for the first 10 items. Some more examples are:
// set some properties of the current object Set Field_Current_Value Field Customer.Name To "Fred" Set Field_Mask Field Customer.Phone To "(###)########" // set some properties of an external data dictionary Set Field_Default_Value of oOrderDD Field Order.Date To dToday Set Field_Mask of oOrderDD Field Order.ContactPhone ; To "(###)########"

Classes

Refer to the DataDictionary class in the Class Reference On-line help for more information about Field and File_Field properties. Some Procedure Set methods that require special parameters are also written the following way:
Set {method-name} {value} [of {object-ID}] Item {item-id} To

The Item keyword is can be used to designate that the first parameter {itemid} is an item or indexed value. The inclusion or exclusion of the Item keyword has no effect on your program. The use of this keyword is being phased out of Visual DataFlex. Refer to the section on Method Overloading for more information on calling procedure methods.

Calling Function Methods


Calling a Function method is complementary to calling a Procedure Set

69

Chapter 8
method (i.e., if a Procedure Set method is used to set a property, then there is usually a Function method that is used to read it). A function method is executed by using a Get statement. The general syntax of the Get statement is:
Get {method-name} [of {object-ID}] {param1 paramN} ; To {receiving-variable}

where {method-name} is the name of the Function method that is being executed: {object-ID} is a handle to the object whos method is being executed {param1 paramN} are all parameters that are passed to the Function method and {receiving-variable} is the variable that is assigned the value returned by the Function method

Classes

The order of the parameters must match the list of parameters in the method's declaration. The parameters you pass can be either constants, variables or expressions, so long as they are of comparable type to the matching parameters in the method declaration. If you are calling a Function method of the current object (current instance of the class) then you can use the Self keyword as the object-id. See the section on The Self Keyword below for more details. Alternatively you can omit the object-id clause completely and DataFlex will automatically reference the current object. Function methods are often used, in conjunction with Procedure Set methods, to simulate a Property. If the function method does not contain any parameters then the syntax for calling the method is identical to reading a property. Some examples of calling Function Methods are:
Get Can_Delete To bCanDelete

For iCount From 0 To 9 Get String_Value of oAnArray Showln sValue Loop

iCount

To sValue

// Call some function methods of the current object Get Field_Current_Value Field Customer.Name To sName Get Field_Mask Field Customer.Phone To sPhoneMask

70

Visual DataFlex Language Guide


// Call some function methods of an external data dictionary Get Field_Default_Value of oOrderDD Field Order.Date ; To dOrderDate Get Field_Mask of oOrderDD Field Order.ContactPhone ; To sMask

Refer to the DataDictionary class in the Class Reference On-line help for more information about Field and File_Field properties. Refer to the section on Method Overloading for more information on calling procedure methods.

Constructors and Destructors


Constructors and Destructors are specialized event methods that control construction and destruction of objects. Each is specified as a method of the class just like any other method except that the method names Construct_Object and Destroy_Object are used. Construct_Object Construct_Object is the name used to declare a constructor method for your class. Constructors are used to create new properties, create nested objects and initialize the object. The syntax for declaring a constructor method is:
Procedure Construct_Object {local variable declarations} {statements} Forward Send Construct_Object {more statements} End_Procedure

Classes

The first action of a constructor is almost always to call the inherited constructor to create and initialize all the inherited attributes of the object. This is performed by using the Forward Send Construct_Object statement. See Augmenting inherited Methods. An example of a class declaration with a constructor method is:
Class cMyEdit is a Edit Procedure Construct_Object Forward Send Construct_Object Property String psName "John" On_Key Key_Alt+Key_X Send Delete_Data

71

Chapter 8
End_Procedure End_Class

In this example the constructor firsts initializes the inherited attributes, then creates a new property, then executes an On_Key statement to declare an accelerator key setting. Refer to Declaring Properties on page 54 and Private Objects on page 75 for further information. Destroy_Object Destroy_Object is the name used to declare a destructor method for your class. Destructors are invoked whenever an object is being destroyed. The syntax for declaring a destructor method is:
Procedure Destroy_Object {local variable declarations} {statements} Forward Send Destroy_Object {more statements} End_Procedure

Classes

The first action of a destructor is almost always to call the inherited destructor. This is performed by using the Forward Send Destroy_Object statement. See Augmenting Inherited Methods. An example of a class declaration with a destructor method is:
Class cMyEdit is a Edit Procedure Destroy_Object Send Info_Box "We are destroying this object" Forward Send Destroy_Object End_Procedure End_Class

Note: You should never send the messages Construct_Object or Destroy_Object. These are event methods that are automatically executed whenever an object is being created or destroyed. Objects are constructed when an object declaration statement is executed. If you wish to manually destroy an object you should execute the Request_Destroy_Object message.

Augmenting Inherited Methods


Each method that is inherited from a superclass can be augmented to perform

72

Visual DataFlex Language Guide


some different action in the new class. If there is no augmentation then the inherited methods will perform as defined in the superclass. An inherited method is augmented simply by creating a new definition for the method in your class definition. The following example demonstrates augmenting an inherited method:
Class cMessageButton1 is a Button Procedure DoShowSomething Send Info_Box "First Message" End_Procedure Procedure OnClick Send DoShowSomething End_Procedure End_Class

Classes

Class cMessageButton2 is a cMessageButton1 Procedure DoShowSomething Send Info_Box "Second Message" End_Procedure End_Class

In this example, the first class cMessageButton1 defines a new method DoShowSomething that displays the message "First Message". Thus the object of this class, when clicked, would show the message "First Message". The second class cMessageButton2 inherits DoShowSomething and OnClick from cMessageButton1, but it augments DoShowSomething to display a different message. An object of this class, when clicked, would show the message "Second Message." Message Forwarding A more sophisticated way to augment an inherited method involves forwarding. Message forwarding allows you to augment an inherited method in such a way that it can perform its inherited action and some new action. All three method types can be forwarded (Procedure, Procedure Set and Function). Messages are forwarded by executing a Forward statement. The syntax for forwarding a message is different for each type of method as outlined below:

73

Chapter 8
Forwarding Procedure Methods
Forward Send {method-name} {Param1 ParamN}

Forwarding Procedure Set Methods


Forward Set {method-name} {Param1 ParamN} valueN} To {value1

Forwarding Function Methods


Forward Get {method-name} {Param1 ParamN} variable} To {receiving-

Classes

You can see that the syntax for forwarding a message is the same as the syntax for executing a method except that the Forward command is appended to the front of each statement. There is also no object reference when forwarding a method. You are always forwarding the message to the superclass of the current object. An example of method augmentation with message forwarding follows:
Class cMessageButton is a Button Procedure Construct_Object Forward Send Construct_Object Property String psMessage Public "First Message" End_Procedure Procedure OnClick Local String sMessage Get psMessage To sMessage Send Info_Box sMessage End_Procedure End_Class

Class cShowLabelButton is a cMessageButton Procedure Set Label String sLabel Forward Set Label To sLabel Set psMessage To sLabel End_Procedure End_Class

In this example the first class augments the Construct_Object method cMessageButton to define a new string property. Note that Construct_Object is forwarded to ensure that all the superclasss attributes are inherited. The OnClick event method is augmented to show the value of the new string

74

Visual DataFlex Language Guide


property in a message box. The second class cShowLabelButton inherits the behavior of cMessageButton, but it also augments the inherited Procedure Set Label method so that the message that is shown when the button is clicked is the same as the buttons label. The Forward Set Label statement is important because, without it, the Set Label method would no longer be able to set the buttons label.

Private Objects
Visual DataFlex classes can be defined to contain nested objects of any other class. Each time an instance of the new class is created the nested objects are also created. Nested objects are useful tools for defining classes that have sophisticated behavior and data storage requirements. Nested objects that are part of a classs definition become private attributes of the class. That is, they are part of the classs internal design. Whenever an object is destroyed, any nested objects it defines are also automatically destroyed. Nested objects are declared in the classs constructor method (Construct_Object). Below is an example class definition that contains a nested object:
Class cStorageForm is a Form Procedure Construct_Object Forward Send Construct_Object Object oStorageArray End_Object End_Procedure is an Array

Classes

Procedure DoAppendValue Integer iItemCount String sFormValue Get Value of Self 0 Get Item_Count of oStorageArray Set Array_Value of oStorageArray sFormValue End_Procedure Procedure DoClearStorage Send Delete_Data To oStorageArray End_Procedure Function StorageValue Integer iItem

To sFormValue To iItemCount iItemCount To

Returns String

75

Chapter 8
String sReturnValue Get String_Value of oStorageArray sReturnValue Function_Return sReturnValue End_Function End_Class iItem To

The above example defines a new Form class cStorageForm that contains a nested array object. Three methods are defined as an interface to the nested array. DoAppendValue retrieves the Form objects value and appends it to the nested array; DoClearStorage clears the data in the nested array and StorageValue returns an indexed value from the array. The methods defined in this example call methods from the current object and from the nested array object. For the purpose of clarity the Self keyword has been used when calling a method of the current object. However, this is redundant since the current object is the default recipient of any message.

Classes

The Self Keyword


The Self keyword is defined as a reference to the current object (current instance of the class). Wherever a statement requires a handle to some object the Self keyword can be used when you wish to reference the current object. The current object is whatever object is currently executing code. For example, if you click on a Button object it will execute its OnClick method. During execution of the OnClick method that particular Button is the current object.

Multiple-Inheritance
Each class that you declare automatically inherits all of the components of its superclass. Visual DataFlex also supports the ability to import the methods of other classes that are not part of the superclass. A class declaration imports the methods of a class (other than its superclass) by executing an Import Protocol statement in its class definition. The syntax of the import protocol statement is shown below:
Import_Class_Protocol {imported-class}

where {imported-class} is the name of the class whose attributes are being imported. For more information on Import Protocol statements refer to the

76

Visual DataFlex Language Guide


Import_Class_Protocol command in the Visual DataFlex Language Reference. An example of a class definition with multiple inheritance is shown below.
Class cMessage_Mixin is a Mixin Procedure Define_cMessage_Mixin Property String psMessage "" End_Procedure Procedure DoShowMessage String sMessage Get psMessage To sMessage Send Info_Box sMessage End_Procedure End_Class

Classes

Class cMessageButton is a Button Import_Class_Protocol cMessage_Mixin Procedure Construct_Object Forward Send Construct_Object Send Define_cMessage_Mixin // important!!! End_Procedure Procedure OnClick Send DoShowMessage End_Procedure End_Class

The above example declares two new classes. The first one, cMessage_Mixin, is designed specifically to be mixed into the class definition of some other class using the multiple-inheritance model. Classes designed for this purpose are called Mixin classes (they are based on the DataFlex Mixin class). You would never instantiate objects of any Mixin class; they are designed only as building blocks for other classes. The second class in the example, cMessageButton, is based on the button class but it also imports all methods from the cMessage_Mixin class. Notice that the constructor method of this class calls the inherited Define_cMessage_Mixin method. This is important because it demonstrates how properties can be defined in a Mixin and then imported. Properties defined in the constructor of a Mixin class would not get imported because the Mixins constructor is never called.

77

Chapter 8
The way that Visual DataFlex works is to only import the methods that are directly defined in the class that is being imported. Thus the imported classs own inherited methods are not imported; neither are its property definitions or private objects. Strictly speaking, this is not multiple-inheritance. Instead, it can be thought of as importing the skills of another class. Importing class skills (or methods) is less complicated and more useful than full multiple-inheritance because it eliminates the possibility of an unwanted clash of method definitions. Such a clash would otherwise occur when the superclass of the imported class contains a method or property that is also defined in the superclass of the new class that you are creating.

Classes

78

Visual DataFlex Language Guide

Chapter 9 - Objects
An object is an instance of a class. It is a dynamically allocated block of memory with a layout that is defined by its class type. To utilize the functionality of a class you must instantiate it as one or more objects.

Object Declaration
Objects are instantiated by executing an object declaration statement. The syntax of the object declaration statement is:
Object {object-name} is a {class-name} {property-settings}

Objects

{nested-object-declarations} End_Object

where {object-name} is the name of the new object and {class-name} is the class that the object is derived from. You may initialize any properties that belong to the objects class inside the object declaration block. Object declarations can also be nested allowing you to declare one object inside another. Refer to Object Nesting on page 81 for more information. An example of an object declaration is:
Object oOK_Button is a Button Set Location to 20 90 Set Label to "OK" End_Object

The above example declares an object of the Button class and initializes the Location and Label properties. The DataFlex naming convention for objects is to prefix the object name with the letter 'o'. This will help you to identify and separate object names from other identifiers in large applications. Declaring new properties and methods in an object is a very useful feature of the Visual DataFlex language. It is quite common that each instance of a class will need to have slightly different attributes and/or methods. To declare a new class for each slight variation is quite tedious. Another way would be to design more flexible classes but the disadvantage here is that this flexibility often introduces unwanted complexity.

79

Chapter 9 Declaring New Properties


DataFlex supports the creation of new properties inside an object declaration statement. These properties are referred to as object-properties. ObjectProperties are unique to the object they are being declared in and are not shared by other objects of the same class. The following example demonstrates how you can define a new property within an object declaration statement:
Object oOK_Button is a Button Set Location to 20 90 Set Label to "OK" Property Integer piClickCount End_Object 0

Objects

Refer to Properties on page 54 in the Chapter 8 - Classes chapter for more information.

Declaring New Methods


In addition to creating object-properties, DataFlex supports the creation of new methods inside an object declaration statement. These methods are unique to the object they are being declared in and are not shared by other objects of the same class. The following example demonstrates how you can define a new method within an object declaration statement:
Object oOK_Button is a Button Set Location to 20 90 Set Label to "OK" Property Integer piClickCount 0

Procedure OnClick Integer iClickCount Forward Send OnClick Get piClickCount To iClickCount Set piClickCount To (iClickCount + 1) End_Procedure End_Object

In the above example the classes OnClick method is augmented to increment an integer property. Refer to Methods on page 58 in the Chapter 8 - Classes chapter for more

80

Visual DataFlex Language Guide


information.

Forward Declaring Objects


Objects can be forward declared using the Register_Object statement. Forward declaring allows you to reference an object somewhere in your program before it is formally declared. The compiler would generate an error in some cases if you tried to do this without a forward declaration. The syntax for forward declaring an object is:
Register_Object {object-name}

where {object-name} is the name of the object that you wish to forward declare.

Objects

Object Nesting
Object declarations in Visual DataFlex can be nested, allowing you to declare one object inside another. The outer object is referred to as the parent and the inner objects are its children. The parent object is said to contain its children. Object nesting is analogous to models of things that we see in the real world - for example, the structure of a car. A car can be thought of as a compound object that is constructed from smaller component objects, such as 4-wheels, a chassis, engine, body and so on. Each of these smaller components is also made up from other objects; an engine contains pistons, a crank, valves, etc. A real-world example of a compound object

In terms of a computer application, lets imagine an order entry application. A

81

Chapter 9
typical Order Entry application is composed of many distinct modules: a customer maintenance view, an order entry view; a print orders view; an inventory maintenance view and so on. Each one of these views contains multiple identifiable entities. A customer maintenance view, for example, will contain buttons, edit forms, labels, tabbed forms, combos, etc. A customer entry view demonstrating nested entities

Objects

DataFlex represents this structure by nesting objects of different types inside each other. The structure of objects that you create in an application will be determined by its design specification. Below is the DataFlex object structure that was used to define the customer entry view shown above.
Object Customer is a dbView Set Label to "Customer Entry View" Set Size to 162 283 Object Customer_DD is a Customer_DataDictionary End_Object Set Main_DD to (Customer_DD(Self)) Set Server to (Customer_DD(Self)) Object Customer_Number is a dbForm Entry_Item Customer.Customer_number Set Label to "Customer Number:"

82

Visual DataFlex Language Guide


Set Size to 13 42 Set Location to 5 72 End_Object Object Customer_Name is a dbForm Entry_Item Customer.Name Set Label to "Name:" Set Size to 13 186 Set Location to 20 72 End_Object Object CustTD is a dbTabDialog Set Size to 105 265 Set Location to 36 7 Object Address_TP is a dbTabPage Set Label to "Address" Object Customer_Address is a dbForm Entry_Item Customer.Address Set Label to "Street Address:" Set Size to 13 180 Set Location to 8 62 End_Object Object Customer_City is a dbForm Entry_Item Customer.City Set Label to "City/State/Zip:" Set Size to 13 84 Set Location to 24 62 End_Object Object Customer_State is a dbComboForm Entry_Item Customer.State Set Size to 13 32 Set Location to 24 152 End_Object // etc. End_Object Object Balances_TP is a dbTabPage Set Label to "Balances" Object Customer_Credit_Limit is a dbForm Entry_Item Customer.Credit_limit Set Label to "Credit Limit:"

Objects

83

Chapter 9
Set Size to 13 48 Set Location to 9 72 End_Object // etc. End_Object Object Comments_TP is a dbTabPage Set Label to "Comments" Object Customer_Comments is a dbEdit Entry_Item Customer.Comments Set Size to 60 242 Set Location to 15 9 End_Object End_Object End_Object End_Object

Objects

Note that this example uses the Entry_Item command. Refer to the Language Reference On-line help for more information on this command.

Delegation
The DataFlex Send, Set and Get statements instruct an object to execute a method. We say that the object receives a message (or instruction) to execute a method. If the object does not have a definition for the method then the message will be automatically passed to the objects parent. This is repeated until either the message is resolved or the message is passed to the outermost parent and is still not resolved. When a message is unresolved in this way, an error is raised. The process of passing an unresolved message on to the parent object is called delegation. The following is an example of object design that takes advantage of message delegation.
Object oButtonPanel is a Panel Set Size to 50 70 Procedure DoClose Send Info_Box "Goodbye!" Send Deactivate End_Procedure

84

Visual DataFlex Language Guide


Object oButton1 is a Button Set Location To 10 10 Set Label To "Button 1" Procedure OnClick Send Info_Box "I am button #1" Send DoClose End_Procedure End_Object Object oButton2 is a Button Set Location To 30 10 Set Label To "Button 2" Procedure OnClick Send Info_Box "I am button #2" Send DoClose End_Procedure End_Object End_Object

Objects

When clicked, both buttons send DoClose to the current object (themselves). However neither button has a definition for the DoClose method therefore this message would be delegated and resolved by the parent object oButtonPanel. Note that the objects in the above example define methods as part of the object definition rather than creating a sub-class. This was done for simplicity and to demonstrate how delegation occurs more clearly. Explicit Delegation You can explicitly delegate a message to the current objects parent by executing a Delegate statement. An explicitly delegated message directly instructs the current objects parent to execute a method. If this method is not resolved in the parent then the normal flow of message delegation will continue to the grandparent object and so on. All three method types can be explicitly delegated (Procedure, Procedure Set, and Function). The syntax for delegating a message is different for each type of method as outlined below: Delegating Procedure Methods
Delegate Send {method-name} {Param1 ParamN}

85

Chapter 9
Delegating Procedure Set Methods
Delegate Set {method-name} {Param1 ParamN} valueN} To {value1

Delegating Function Methods


Delegate Get {method-name} {Param1 ParamN} variable} To {receiving-

You can see that the syntax for delegating a message is the same as the syntax for executing a method except that the Delegate command is appended to the front of each statement. There is also no object reference when delegating a method. You are always delegating the message to the parent of the current object.

Objects

The following is an example of object design that takes advantage of explicit message delegation.
Object oPanel Set Size is a Panel to 50 70

Object oButton1 is a Button Set Location To 10 10 Set Label To "Button 1" Procedure OnClick Send Info_Box "I am button #1" Delegate Send Deactivate End_Procedure End_Object Object oButton2 is a Button Set Location To 30 10 Set Label To "Button 2" Procedure OnClick Send Info_Box "I am button #2" Delegate Send Deactivate End_Procedure End_Object End_Object

In the above example, the "Delegate Send Deactivate" statement ensures that it is the object oPanel that executes the Deactivate method. If this message was not delegated, then each button would try to deactivate itself when it was clicked rather than deactivate the whole panel since the Button

86

Visual DataFlex Language Guide


class also understands the Deactivate method. Refer to Methods on page 58 in the Classes chapter for more information on calling methods.

Sending Messages to Objects


As already described the standard syntax for sending messages are:
Send {method-name} Get {method-name} Set {method-name} [of [of To [of To {object-ID}] {param1 paramN} {object-ID}] {param1 paramN} ; {receiving-variable} {object-ID}] {param1 paramN} ; {setting-variable}

where {object-ID} is a handle to the object that will receive and execute the method. There are several ways to obtain the handle of an object.

Objects

Sending a Message to Yourself


Often an object will send a message to itself. This means that the object that is sending the message is also the object receiving the message. When this occurs the predefined keyword Self can be used to identify the object ID. In the following example, all messages within an object based on this class are sent to itself, so Self is used to identify the object-ID of each message.
Class cMyButton is a Button Procedure Construct_Object Forward Send Construct_Object Property Integer piClickCount 0 End_Procedure Procedure DoAction Integer iCount Get piClickCount of Self to iCount Move (iCount+1) to iCount Set piClickCount of Self to iCount End_Procedure Procedure OnClick Send DoAction of Self End_Procedure End_Class

87

Chapter 9
Because this type of message sending occurs so often, the {of self} syntax may be omitted. When an object-ID is not identified, the current-object (self) is assumed. Therefore, the above example could be more easily written as:
Class cMyButton is a Button Procedure Construct_Object Forward Send Construct_Object Property Integer piClickCount 0 End_Procedure Procedure DoAction Integer iCount Get piClickCount to iCount Move (iCount+1) to iCount Set piClickCount to iCount End_Procedure Procedure OnClick Send DoAction End_Procedure End_Class

Objects

Sending a Message to Another Object


When a message is sent from one object to another, the destination objects handle must be obtained. This is done by moving the objects ID to a handle and using that variable as the object-id.
Move oSomeObject to hoHandle Send MyMessage of hoHandle

For example:
Procedure DoAction Handle hoButton1 Handle hoButton2 String sLabel1 String sLabel2 Move oButton1 to hoButton1 // contains object ID of button1 Move oButton2 to hoButton2 // contains object ID of button2 Get Label of hoButton1 to sLabel1 Get Label of hoButton2 to sLabel2 Send GenerateNewLabel of hoButton1 sLabel1 Send GenerateNewLabel of hoButton2 sLabel2

88

Visual DataFlex Language Guide


End_Procedure

In the above example, object handles were moved to a variable and the variable was then used in the message. The Move command is used to move the objects handle to the variable. This command actually generates an internal expression that generates a handle for the object and assigns it to the variable. The method used to generate this handle will be discussed shortly. Alternately, you can reference the object name directly within the message bypassing the need to create a handle variable. This sample could have been rewritten as:
Procedure DoAction String sLabel1 String sLabel2 Get Label of oButton1 Get Label of oButton2 Send GenerateNewLabel Send GenerateNewLabel End_Procedure

to to of of

sLabel1 sLabel2 oButton1 sLabel2 oButton2 sLabel1

Objects

This method requires less code and is easier to read. While this second method makes it easier to write code, there is an optimization issue that must be understood. When an object name is used directly within a message, its handle must be evaluated each time it is used (just as the object handle must be evaluated in the Move command). This evaluation is not as efficient as using a handle variable. Therefore, if the same object is going to be accessed many times within the same method, you will probably want to move the object handle to a variable and then use the variable to send the message. This way the object handle only needs to be evaluated one time. For example:
Procedure DoAction Handle hoArray Integer iCount // Non-Optimized: this method will be slower Send delete_data of oMyArray1 for iCount from 0 to 10000 // oMyArray must be evaluated each time it is used Set value of oMyArray1 iCount to "Test" Loop // Optimized: this method will be slightly faster. Move oMyArray2 to hoArray // oMyArray2 is evaluated once

89

Chapter 9
Send delete_data of hoArray for iCount from 0 to 10000 Set value of hoArray iCount to "Test" Loop End_Procedure

The optimization involved here is quite small. In most cases, you will not be able to perceive a performance difference between the two techniques.

Passing Object Handles as a Parameter


The discussion of object IDs have been limited to using them to determine which object receives a message. In some cases, you may need to pass an object handle as a parameter within a message. In such a case you must use the move command to move the object ID to a handle variable and pass the variable. You may not pass the object name directly. The following example shows the right way and the wrong way to pass an object handle as a parameter. In this example we are trying to send a message to oButton1 passing as a parameter the object handle of oButton2.
// this is the correct way Procedure GoodAction Handle hoButton2 // first move object handle to variable Move oButton2 to hoButton2 // then, pass the variable Send NotifyButton of oButton1 hoButton2 End_Procedure // this will NOT work. You will get a compile error Procedure BadAction Send NotifyButton of oButton1 oButton2 End_Procedure

Objects

Relative Object Name Access


The object access method described above is relative. An object handle is determined by an objects name relative to the object that sent the message. The use of relative object addressing makes it possible to maintain proper encapsulation while at the same time providing an object access scheme that is easy to code and easy to maintain. Relative object addressing is an important part of the DataFlex object model and should be thoroughly understood.

90

Visual DataFlex Language Guide


Good object-oriented programming style states that an object should only need to know about objects that exist within its immediate environment or scope. An object can be aware of itself, its immediate children, and it parents (ancestors). Specifically an object should not directly know about or directly send messages to grandchild objects (or any other descendant objects). To do so would breach encapsulation, making programs much harder to write and maintain. If an object needs to communicate with an object that is out of its reach, your object message interface should be changed. For example, if an object needs to communicate with a grandchild object you should change your interface so that the object can send a message to its child (which is within its scope) and the child would then send a message to the grandchild (which is in its scope). The DataFlex object accessing method allows you to directly access all objects that you should be able to access. When an object handle is requested, through either a move command (move oMyObj to hoMyObj) or as part of message (Send MyMgs of oMyObj) the following steps are taken to find the named object and return its handle ID. 1. 2. The object sending the message looks for a child object with the target name. If an object is found, the objects handle is returned. The object sending the message checks to see if there is a properly named sibling object. If found, a handle is returned. At this point it is actually looking at the parents child-objects. The object sending the message will now look at all child objects belonging to its grandparent object (siblings of the parent). If found, the handle is returned. This process of moving up to an ancestor object and checking all children continues until an object is found, or the outer-most parent is tested and the target is still not found, in which case a handle value of zero is returned.

Objects

3.

4.

This means that an objects scope consists of: itself its children its ancestors (parents, grand-parents, etc.) all sibling objects of all ancestors.

Consider the following object structure:

91

Chapter 9
Object oArray1 is an Array End_Object Object oArray2 is an Array End_Object Object oPanel is a Panel Object oContainer1 is a Container3d Object oButton1 is a Button End_Object Object oButton2 is a Button End_Object End_Object

Objects

Object oContainer2 is a Container3d Object oButton1 is a Button Object oArray1 is an Array End_Object End_Object Object oButton2 is a Button Object oArray3 is an Array End_Object End_Object End_Object End_Object

Object oArray1 has no parents and no children. Therefore, it can send messages to itself and its siblings, oArray2 and oPanel. Similarly, oArray2 can send messages to itself and oArray1 and oPanel. Object oPanel has children but no parents. Thus, it can send messages to itself, oContainer1, oContainer2, oArray1 and oArray2. It can not send messages to any of the button objects. These grandchild objects are out of its scope. Object oContainer1 has children, siblings, and parents. It can send messages to itself, its children - oButton1and oButton2, oContainer2, oPanel, oArray1 and oArray2. Note that it can not send message to the children of oContainer2. The button objects within oContainer1 and oContainer2 have the same names. This is allowed and is actually encouraged. This will never be a problem because the objects cannot be addressed at the same time (they are in different scopes). Object oButton1 inside of oContainer1 can send messages to itself, oButton2,

92

Visual DataFlex Language Guide


oContainer1, oContainer2, oPanel, oArray1 and oArray2. Note that the oButton1 object inside of oContainer2 contains an array object (oArray1) that has the same name as a parent array object. In this case, both of these array objects are within scope for oButton2. When duplicate object names exist within the same scope, the first object encountered (in this case the child object) will receive the messages. Relative object access is actually much harder to describe than it is to use. Just remember, when you send messages to objects you will always use the objects relative name (e.g. oButton1). If the object is found, the object is in scope and your program is proper. If the object is not found, the object is out of scope and your program needs to be corrected. This relative object access method is one of the cornerstones of the DataFlex Application Framework (which is discussed in other documents). This method is used to create views, create and connect data-dictionary object structures, and create nested data-entry objects that all properly and elegantly connect to the proper data-dictionary objects.

Objects

Long and Short Object Names


Each object has a long name and a short name. The short name is its relative name and is the name that you will use to access objects. This name is stored in a property called Object_Label. Any objects relative name can be retrieved with the following code:
Get Object_Label to sName

Examples of short object names are:


oArray1 oPanel oContainer1 oButton1

An objects long name consists of its short name and all of the short names of its ancestor objects. This name is stored in a property called Name. Any objects long name can be retrieved with the following code:
Get Name to sName

Examples of long object names are:


oArray1 oPanel

93

Chapter 9
oPanel.oContainer1 oPanel.oContainer1.oButton1 oPanel.oContainer2.oButton1.oArray1

Other Object Access Methods


As you look through sample code and package code you will see that objects are often accessed using an object access expression syntax. This syntax has the format of:
(objectName(Self)) or (ObjectName(Current_Object))

This is an older style of coding that, while still valid, has been replaced with the simpler methods discussed here. The following two code segments generate the same compiled code:

Objects

Send MyMessage of (oMyObject(Self)) Get MyProperty of (oMyObject(Self)) to iVar Move (oMyObject(self)) to hObj

And
Send MyMessage of oMyObject Get MyProperty of oMyObject to iVar Move oMyObject to hObj

There will be times when you will need to use the object access expression syntax. The expression syntax must be used if you are accessing an object within an expression. The following code will not compile:
Move (Label(oMyObject)) to sLabel

The proper code would be:


Move (Label(oMyObject(Self))) to sLabel

Of course, much of this confusion can be avoided if you use the suggested syntax of:
Get Label of oMyObject To sLabel

The expression syntax must also be used if you insist on accessing objects that are outside of an objects relative scope.
Move (oRadio1(oRadioGroup(oMyView(self)))) to hoRadio1

The syntax can also be used to access an object by its absolute location:

94

Visual DataFlex Language Guide


Move (oRadio1(oRadioGroup(oMyView(oClientArea(oPanel(desktop)))))) to hoRadio1

The complexity of this code speaks for itself and should and can be avoided. Refer to Chapter 12 - Accessing Class Attributes with Expressions on page 109 for more information regarding expression syntax.

Objects

95

Visual DataFlex Language Guide

10

Chapter 10 - Programs
Visual DataFlex programs have a very free format structure. Most of the program is made up of individual source code files called packages. Packages are the basis of modular programming in Visual DataFlex. They are used to create libraries that you can include in various programs, and to divide large programs into logically related modules.

Using Packages
Packages are included into the body of a program via the Use Statement. The syntax of the Use statement is:
Use {package-name}

Programs

where {package-name} is the file name of the package file that will be included. The Use statement is a compiler directive instructing the compiler to merge the source code of the package file into the program at the point where the Use statement occurs. Source code packages can also contain Use statements. The compiler keeps track of each package that is used and will ignore a Use statement if the package has already been included once. Visual DataFlex also has a #INCLUDE compiler directive for merging external source packages. The difference is that the #INCLUDE command can be used to merge-in multiple copies of the same package file. Refer to the Language Reference On-line help for more information on the #INCLUDE compiler directive.

Simple Programs
Most Visual DataFlex programs will conform to at least the following basic structure:
Use Windows.pkg {use all other necessary packages} {declare global variables} {declare global functions & procedures}

97

Chapter 10
{define a panel object} Start_UI

In the above structure the Use Windows.pkg instructs the compiler to include a library of basic definitions that are needed to write a simple Windows program. A Visual DataFlex program will define at least one object. It is necessary to include the class definitions for each objects class. These definitions are stored in external package files. Refer to Using Packages on page 97 for more information. The Start_UI statement is required to start the event driven user interface engine. Without a Start_UI the program will simply create all of the defined data structures then exit. An example of a simple Visual DataFlex program that displays a single panel object is shown below:
Use Windows.pkg Use DFPanel.pkg Object oPanel is a Panel Set Label to "Visual DataFlex" Set Size to 80 150 End_Object Start_UI

Programs

Refer to the Visual DataFlex Developing Applications Guide for information on how to build large-scale database applications.

Pre-Compilation
Visual DataFlex allows you to mark a section at the top of your program for pre-compilation. Programs that contain a pre-compiled section will compile faster. The main restriction on the pre-compiled portion of your program is that it must be the first part of your program. If any lines of code are placed above the section that you have marked for pre-compilation then the compiler will continue as though none of your program is pre-compiled. There are two ways to achieve pre-compilation: Pre-compiled packages: You can pre-compile any package file, if the Use statement for a pre-compiled package is on the first line of your

98

Visual DataFlex Language Guide


program then the compiler will use the pre-compiled code. #HEADER #ENDHEADER compiler directives: These directives mark a block of code for pre-compilation. You may not use a #HEADER #ENDHEADER pair to split any compound statement (such as an object declaration).

An example of a program with a block marked for pre-compilation is shown below:


#HEADER Use Windows.pkg Use DFPanel.pkg #ENDHEADER Object oPanel is a Panel Set Label to "Visual DataFlex" Set Size to 80 150 Object oButton Is A Button Set Location to 40 10 Set Label to "Exit" Procedure OnClick Delegate Send Deactivate End_Procedure End_Object End_Object Start_UI

Programs

Refer to the Compiler On-line help for more information on pre-compiling packages and programs.

99

Visual DataFlex Language Guide

11

Chapter 11 - Sequential File Input and Output


Introduction
A text file is considered to represent a sequence of characters formatted into lines, where each line is terminated by an end-of-line marker. This section describes the capabilities and techniques for performing sequential I/O to text files in Visual DataFlex.

Opening Sequential I/O Files


Visual DataFlex can read data from, and write data to, up to ten sequential I/O files simultaneously. Before you can read or write sequential data you must first open the file. The syntax for opening a file for input (reading) is:
direct_input [channel {channel-num.}] {file-name}

Seq. File Input/Output

and the syntax for opening a file for output (writing) is:
direct_output [channel {channel-num.}] {file-name}

where {channel-num.} is the assigned channel for the file that is being opened and {file-name} is the name and path of the file that is being opened. {filename} can be a string token, string variable or a string expression. Examples of opening a file for sequential I/O are:
direct_input "c:\myDocs\Readme.txt" direct_output sErrorLog

Assigning an Explicit I/O Channel Whenever a file is opened for I/O it is assigned an I/O channel. Visual DataFlex supports up to ten channels for simultaneous sequential file I/O. The channels are numbered 0..9. The default channel for input is channel 0; the default channel for output is 1. The channel that you assign to a file when it is opened for sequential I/O must be unused. When you close a file for sequential I/O the channel that was assigned to it becomes available for reuse. Examples of opening a file for sequential I/O and explicitly assigning a channel number are:

101

Chapter 11
direct_output channel 3 "c:\myDocs\Readme.txt" direct_output channel iOutChannel "c:\autoexec.bat"

Testing for Valid Input Files If the file named in a direct_input statement cannot be opened then the Boolean expression Seqeof returns True. The following example demonstrates how you can test for a valid input file name.
direct_input sActivityLog If (seqeof) Showln "Error: cant open " sActivityLog

Appending Data to an Output File

Seq. File Input/Output

If the file that is named in a Direct_Output statement already exists then the contents of the existing file are deleted and replaced with whatever data is written to it. To append data to the end of an existing file you should use the DataFlex Append_Output command to open the file. The syntax of the Append_Output command is:
Append_Output [channel {channel-num.}] {file-name}

where {channel-num.} is the assigned channel for the file that is being opened; and {file-name} is the name and path of the file that is being opened. {file-name} can be a string token, string variable or a string expression. Examples of opening files using Append_Output is:
Append_Output sErrorLog Append_Output Channel 3 "c:\temp\activitylog.txt"

Reading and Writing Data


Reading Data
There are four DataFlex commands for reading data from a sequential I/O file. They are: Read, Readln, Read_Block, and Read_Hex. The first three are detailed below. Refer to the Language Reference On-line help for more information about each of these commands. Read The Read command reads comma-delimited data from the input file starting from the first line of the input file until it finds a comma or end-of-line character. Then it moves the data to a variable. The syntax for the Read

102

Visual DataFlex Language Guide


command is:
Read [channel {channel-num.}] variableN}] {variable1} [{variable2 ..

where {channel-num.} is the channel assigned to the file that is being read. {variable1 .. N} are variables that will be assigned the values that are read in. If the channel specification is omitted then data is read from whichever channel was last referenced, or channel 0 if no channel has been referenced. Each Read command must specify at least one variable for receiving the read data. Successive Read statements pick up at the end of the last data that was read, until an end-of-line character is encountered. To read past an end-of-line character in a data file, you must use a Readln command. When an end-ofline character is encountered, the Boolean expression seqeol returns True. When an end-of-file character is encountered, the Boolean expression seqeof returns True. An example of using the Read command is:
Direct_Input "c:\Names.txt"

Seq. File Input/Output

Repeat Read sFirstName Read sLastName If (Seqeol) Readln Until (seqeof) Close_Input

You can specify more than one {variable} per Read command. This is equivalent to executing multiple Read commands, one per {variable}. The Repeat statement in the previous example could be rewritten as shown below:
Repeat Read sFirstName sLastName If (Seqeol) Readln Until (seqeof)

Readln The Readln command reads data from the input file starting from the first line of the input file it finds an end-of-line character. Then it moves the data to a variable. The syntax for the Readln command is:

103

Chapter 11
Readln [channel {channel-num.}] [{variable1} .. variableN}]

where {channel-num.} is the channel assigned to the file that is being read. {variable1 .. N} are variables that will be assigned the values that are read in. If the channel specification is omitted then data is read from whichever channel was last referenced, or channel 0 if no channel has been referenced. If no {variable} is specified in the Read command the data is read in, then discarded. Successive Readln statements pick up at the end of the last data that was read. After each Readln the Boolean expression seqeol returns False. When an end-of-file character is encountered, the Boolean expression seqeof returns True. An example of using the Readln command is:

Seq. File Input/Output

Direct_Input

"c:\Names.txt"

Repeat Readln sWholeName Until (seqeof) Close_Input

You can specify more than one {variable} per Readln command. This is equivalent to executing multiple Read commands, one per {variable} followed by a Readln with no variable. Read_Block The Read_Block command reads a specified number of bytes of data from the input file. Then it moves the data to a variable. The syntax for the Read_Block command is:
Read_Block [channel {channel-num.}] {variable} {length}

where {channel-num.} is the channel assigned to the file that is being read; {variable} is the variable that will be assigned the data that is read in; and {length} is the number of bytes that will be read. If the channel specification is omitted then data is read from whichever channel was last referenced, or channel 0 if no channel has been referenced. Successive Read_Block statements pick up at the end of the last data that was read. When an end-of-file character is encountered, the Boolean expression seqeof returns True. An example of using the Read_Block command is:
Direct_Input "c:\PhotoID.bmp"

104

Visual DataFlex Language Guide


Read_Block sPhoto Close_Input 16000

The Read_Block command makes no distinctions among characters in the file (delimiters, spaces, tabs), except the end-of-file character, which delimits the end of the file. Read_Block is intended for use with non-delimited text or binary-data files. You must set the length and the pattern of Read_Block statements according to your prior knowledge of the structure of the data in the input file, since it cannot be inferred from delimiting characters. The maximum length is governed by the maximum number of characters that can be stored in the receiving variable (refer to the section on String variables for further details).

Seq. File Input/Output

Writing Data
There are three DataFlex commands for writing data to a sequential I/O file. They are: Write, Writeln, and Write_Hex. The first two are detailed below. Refer to the Language Reference On-line help for more information about each of these commands. Write The Write command writes data to the output file. Write appends the data to the output file without creating a new line. A Writeln statement must be executed to advance output to the next line. The syntax for the Write command is:
Write [channel {channel-num.}] {value1} [{value2 .. valueN}]

where {channel-num.} is the channel assigned to the file that is being read; {value1 .. N} are the data items that are written. {value} can be any constant, variable or expression. If the channel specification is omitted then data is written to whichever channel was last referenced, or channel 1 if no channel has been referenced. Each Write command must specify at least one {value} to be written. An example of using the Write command is:
Direct_Output "c:\Names.txt"

Write "Bill, Bob, Jane" Writeln Write "Mary, Stuart, John" Writeln

105

Chapter 11
Close_Input

Writeln The Writeln command writes data to an output file then outputs an end-of-line character. The Syntax of the Writeln command is:
Writeln [channel {channel-num.}] [{value1 .. valueN}]

Seq. File Input/Output

where {channel-num.} is the channel assigned to the file that is being read; {value1 .. N} are the data items that are written. {value} can be any constant, variable or expression. If the channel specification is omitted then data is written to whichever channel was last referenced, or channel 1 if no channel has been referenced. If no {value} is specified then the Writeln command will simply add an end-of-line character to the output file. An example of using the Writeln command is:
Direct_Output "c:\Names.txt"

Writeln "Bill, Bob, Jane" Writeln "Mary, Stuart, John" Close_Input

Random Access
After you open a file for input, the first Read or Readln statement will begin reading at the beginning of the file. Each subsequent Read or Readln will continue where the last read finished. In this way, you can progress through the file from start to finish. Similarly, when a file is opened for output, data is always appended to the end of the last data that was written to the file. The DataFlex Set_Channel_Position command allows you to explicitly specify an offset from the beginning of the I/O file where the next read or write operation will occur. The syntax of the Set_Channel_Position command is:
Set_Channel_Position {channel-num.} To {offset}

where {channel-num.} is the channel assigned to the file that you are reading or writing; and {offset} is the number of bytes from the beginning of the file that the next I/O operation will occur. An offset value of 1 specifies that the next I/O operation will occur at the first byte; i.e., the {offset} parameter is not zero-based. An offset value of 1 specifies that the next I/O operation will occur at the end of the file.

106

Visual DataFlex Language Guide


Refer to the Set_Channel_Position and Get_Channel_Position commands in the Language Reference On-line help for more information.

Using Explicit I/O Channels


When more than one channel is used for simultaneous input or output then you must explicitly assign separate channel numbers to each file. The following example demonstrates reading data from three files and writing their combined contents to a fourth.
String sCar sBus sTaxi Direct_Input Channel 2 Direct_Input Channel 3 Direct_Input Channel 4 Direct_Output Channel 5 // Read from cars.txt Repeat Readln Channel 2 Writeln Channel 5 Until (Seqeof) "c:\Cars.txt" "c:\Busses.txt" "c:\Taxis.txt" "c:\Vehicles.txt"

Seq. File Input/Output

sCar sCar

// Read from busses.txt Repeat Readln Channel 3 sBus Writeln Channel 5 sBus Until (Seqeof) // Read from taxis.txt Repeat Readln Channel 4 Writeln Channel 5 Until (Seqeof) Close_Input Close_Input Close_Input Close_Output Channel Channel Channel Channel 2 3 4 5

sTaxi sTaxi

The (seqeof) expression will return the end-of-file status of the last referenced channel number in a Readln command.

Closing Sequential I/O Files


Each I/O file that is opened should be closed when you have finished reading

107

Chapter 11
from or writing to it. Closing the file releases the channel for use with another I/O operation. It also makes the file available to be accessed by some other process. The syntax for closing an input file is:
Close_Input [channel {channel-num.}]

And the syntax for closing an output file is:


Close_Output [channel {channel-num.}]

Seq. File Input/Output

where {channel-num.} is the assigned channel of the file that is being closed. If the channel parameter is omitted then the default input or output channels will be closed.

108

Visual DataFlex Language Guide

12

Chapter 12 - Accessing Class Attributes with Expressions


Reading Properties using Expressions
Visual DataFlex supports two distinct ways to read the Properties of an object. The first syntax is to use a Get statement, the second syntax is to read the property within an expression. The syntax of the Get statement for reading a property is:

Access Class Attributes

Get {property-name}

[of {object-id}]

To {variable-id}

where {property-name} is the name of the property that is being read; {objectid} is a handle to the object whos property is being read; and {variable-id} is the name of a variable that will receive the propertys value. This syntax is fully discussed in the section on Reading Property Values. The syntax of reading a property using an expression is:
({property-name}({object-id}))

Notice that the {object-id} is a compulsory part of the expression syntax for reading a property. If the object property is in the same object as the one sending the message, the keyword self must be used as the object-id. Below is an example of using expression syntax to read a property value, followed by the equivalent Get statements:
Move (Label(Self)) Get Label of self To sLabel To sLabel To sLabel // self is required // self is implied // self is explicit (not

Get Label required)

If the object property is in a different object than the object sending the message, the object must be named using the expression syntax. The expression syntax is written as written as (ObjectName(Self)). This extended syntax is necessary when referencing an object name in an expression. Refer to Other Object Access Methods on page 94 for more information. Below are some examples of using expression syntax to read property values

109

Chapter 12
from another object followed by the equivalent Get statement:
Move (Label(oButton(Self))) To sLabel Get Label of oButton To sLabel

In the above example, the Label property of an object called oButton is read into a variable called sLabel. Notice that in the expression, the object reference for oButton is written as (oButton(Self)). Alternately, the object handle can be moved to a variable and used in an expression as follows:

Access Class Attributes

Handle hoButton Move oButton to hoButton Move (Label(hoButton)) to sLabel

In the following example the Enabled_State property of an object called oButton is evaluated in an If statement.
If (Enabled_State(oButton(Self))) enabled" Showln "This button is

Get Enabled_State of oButton To bEnabled If (bEnabled) Showln "This button is enabled"

The following example shows how multiple properties may be evaluated within a single expression. Several different coding styles are demonstrated that all accomplish the same goal. Style A:
If (Changed_State(oCustomer_DD(Self)) AND ; Allow_Update_State(oCustomer_DD(Self)) AND ; (Find_Mode(oCustomer_DD(Self))=MODE_SAVING)) ; Send DoUpdateStatus

Style B:
Handle hoCustomer_DD Move oCustomer_DD To hoCustomer_DD If (Changed_State(hoCustomer_DD) AND ; Allow_Update_State(hoCustomer_DD) AND ; (Find_Mode(hoCustomer_DD)=MODE_SAVING)) ; Send DoUpdateStatus

110

Visual DataFlex Language Guide


Style C:
Handle hoCustomer_DD Integer bChanged bAllowUpdate iMode Move oCustomer_DD to hoCustomer_DD Get Changed_State of hoCustomer_DD to bChanged Get Allow_Update_State of hoCustomer_DD to bAllowUpdate Get Find_Mode of hoCustomer_DD to iMode If (bChanged AND bAllowUpdate AND (iMode=MODE_SAVING)) ; Send DoUpdateStatus

Style A: uses the expression syntax to evaluate each property and is the most concise. However the If statement has many nested brackets. It is the least readable and most difficult to maintain of the 3-styles. It would also be less efficient to execute than the other two styles. Style B: also uses expression syntax, but the object ID has been evaluated first and is passed to the expression in a Handle variable. This style is slightly more verbose but the If statement is slightly simpler and the code is more efficient. Style C: Is the most verbose. It uses Get statements to retrieve the property values so that they are not evaluated in the If statement. The result is a much simpler If statement. The code would also be more efficient if the properties were used more than once because the values have already been retrieved into variables.

Access Class Attributes

Calling Function Methods using Expressions


Visual DataFlex supports two distinct ways to call Function Methods. The first syntax is to use a Get statement, the second syntax is to call the method within an expression. The syntax of the Get statement for calling a Function method:
Get {method-name} {variable-id} [of {object-id}] {param1 paramN} To

where {method-name} is the name of the Function method that is being executed; {object-id} is a handle to the object whos method is being executed; and {variable-id} is the name of a variable that is assigned the value that is returned by the Function method. This syntax is fully discussed in the section on Calling Function Methods. The

111

Chapter 12
syntax of calling a Function method using an expression is:
({method-name}({object-id}[,param1 ,paramN))

Notice that the {object-id} is a compulsory part of the expression syntax for calling a Function method. The functions parameters follow the {object-id}. Each parameter is delimited by a single comma. If the object being called is the same as the object sending the message, the keyword self must be used as the object-id. Below is an example of using expression syntax to call a function, followed by the equivalent Get statement:

Access Class Attributes

Move (Calc_Sales_Tax(Self, required Get Calc_Sales_Tax implied

nAmount)) To nSalesTax

// self is

nAmount

To nSalesTax

// self is

Get Calc_Sales_Tax of Self nAmount used

To nSalesTax

// self is

If the object being called is a different object than the object sending the message the object must be named using the expression syntax. The expression syntax is written as written as (ObjectName(Self)). This extended syntax is necessary when referencing an object name in an expression. Refer to Other Object Access Methods on page 94 for more information.
Move (Calc_Sales_Tax(oSalesDD(Self),nAmount)) To nSalesTax

or,
Move oSalesDD to hoSalesDD Move (Calc_Sales_Tax(hoSalesDD,nAmount)) To nSalesTax

or,
Get Calc_Sales_Tax of oSalesDD nAmount To nSalesTax

Object functions may also be used as part of complex expressions:


Move (Calc_Sales_Tax(oSalesDD(Self),nAmount)/100) To iSalesTax

or,
Get Calc_Sales_Tax of oSalesDD nAmount To nSalesTax Move (nSalesTax/100) to iSalesTax

112

Visual DataFlex Language Guide


The following example passes two parameters to a function.
Move (Field_Option(oCustomerDD(Self), iField, iOption)) To bOption Get Field_Option of oCustomerDD iField iOption To bOption

The Field_Option example shown above requires that the field number of the field you are querying is stored in the variable :iField. Retrieving this field number requires some special code. The Get statement version of this example can be rewritten in the following way:
Get Field_Option of oCustomerDD FIELD Customer.Name iOption To bOption

Access Class Attributes

where Customer.Name is the field identifier of the field that you are querying. This is a much more convenient way to pass parameters to Function methods that require field numbers. Unfortunately. the expression syntax version cannot pass field identifiers in this way. Refer to DataFlex also supports method overloading. Refer to the section on Method Overloading for information on declaring overloaded Procedure Methods. Declaring Procedure Set Methods on page 60 for more information.

113

Visual DataFlex Language Guide

13

Chapter 13 - Advanced Data Types


Address
DataFlex Address types are used to declare variables for storing the memory address of a variable. You can assign a value to an address variable with the GetAddress command. This command will retrieve the memory address of a named variable and return it to the Address variable.

TYPE
Address

RANGE
0..4294967296

Advanced Data Types

The Address type is primarily designed to be used when making DLL calls to the Windows API. It is used to store the address of Structure variables.

BigInt
The BigInt type is an 8 byte signed integer.

TYPE
Integer

RANGE
-0x8000000000000000 To 0x7fffffffffffffff (approximately -8 * 10 18) 8 * 10
18

to

Char
The Char type is a one byte signed integer.

TYPE
Integer

RANGE
-128127

115

Chapter 13

Currency
The currency type is useful for storing fixed point numbers with 4 or fewer digits to the right of the decimal point and up to 14 to the left. The purpose of this data type is to facilitate integration with COM and ODBC.

TYPE
Integer

RANGE
922337203685477.5807 to -922337203685477.5808

Decimal

Advanced Data Types

Internally, the Decimal is a 17-byte number that can contain any decimal number with up to 16 digits to the left of the decimal point and 16 digits to the right of the decimal point. The external interface is as a SQLNUMERIC_STRUCT as defined in ODBC 1.0.

TYPE
Number

RANGE
9999999999999999.99999 99999999999 to 9999999999999999.99999 99999999999

Float
A Float is a 32-bit IEEE floating point number.

TYPE
Number

RANGE
Mantissa precision 7, 10 38 to 10
-38

Short
The Short type is a two byte signed integer.

TYPE
Integer

RANGE
-32768 to 32767

116

Visual DataFlex Language Guide

UBigInt
The UBigInt type is an 8 byte unsigned integer.

TYPE
Integer

RANGE
0x0 To 0xffffffffffffffff (approximately 0 to 1.6 * 19) 10

UChar
The UChar type is a one byte unsigned integer.

Advanced Data Types

TYPE
Integer

RANGE
0255

UInteger
The UInteger type is a 4 byte unsigned integer.

TYPE
Integer

RANGE
0 4GB minus 1

UShort
The UShort type is a two byte unsigned integer.

TYPE
Integer

RANGE
0 to 65535

Structured Types
A Structure type comprises a set number of fields that can be of different types. The Structure-type declaration specifies the type and name of each field. Structure-types are declared using the following syntax:
Type {type-name} FIELD {type-name}.{field-name} FIELD {type-name}.{field-name} as {field-type} as {field-type}

117

Chapter 13
FIELD {type-name}.{field-name} End_Type as {field-type}

where {type-name} is the name of the new Structure-type; {field-name} is the name of each individual field and {field-type} is the data-type of each field. Each field name in a given Structure type must be unique. Each field may be assigned any DataFlex simple (fixed-length) type. You can chose from: Integer, Real, Date, Pointer, Handle or DWord. You cannot use String as a field type because strings are variable-length. Instead of String there is a comparable fixed-length type called Char that is specially designed for this purpose. The syntax for declaring a Char type field is:
FIELD {type-name}.{field-name} as Char {length}

Advanced Data Types

where {length} is the length in bytes of the character string. The DataFlex Structure type is designed primarily for passing data to and from the Windows API. An example of a Structure type declaration is:
Type TV_ITEM Field TV_ITEM.mask Field TV_ITEM.hItem Field TV_ITEM.state Field TV_ITEM.stateMask Field TV_ITEM.pszText Field TV_ITEM.cchTextMax Field TV_ITEM.iImage Field TV_ITEM.iSelectedImage Field TV_ITEM.cChildren Field TV_ITEM.lParam End_Type as as as as as as as as as as UInteger handle UInteger UInteger pointer UInteger UInteger UInteger UInteger UInteger

Another example that uses the Char data type is:


Type T_Box Field T_Box.Height Field T_Box.Length Field T_Box.Width Field T_Box.Description End_Type as as as as Integer Integer Integer Char 30

118

Visual DataFlex Language Guide Declaring Structure Variables


A Structure variable must first be declared as a string, then converted into a Structure with the ZeroType command. The syntax of a Structure variable declaration is:
String {variable name} ZeroType {variable type} To {variable name}

where {variable name} is the name of the new Structure variable and {variable type} is its declared type. An example of a Structure variable declaration including its type-definition is:
// Declare the Tree View item Type Type TV_ITEM Field TV_ITEM.mask as Field TV_ITEM.hItem as Field TV_ITEM.state as Field TV_ITEM.stateMask as Field TV_ITEM.pszText as Field TV_ITEM.cchTextMax as Field TV_ITEM.iImage as Field TV_ITEM.iSelectedImage as Field TV_ITEM.cChildren as Field TV_ITEM.lParam as End_Type

Advanced Data Types

UInteger handle UInteger UInteger pointer UInteger UInteger UInteger UInteger UInteger

// Declare a Tree View item variable String sTreeViewItem ZeroType TV_ITEM To sTreeViewItem

Accessing Data in a Structure Variable


You need to use special commands to access data in the fields of a Structure variable. The syntax for assigning data to a Structure field is:
Put {value} To {Structure-variable} type}.{field-name} At {Structure-

where {value} is the value that you are assigning to the Structure variable; {Structure-variable} is the name of the Structure variable you are assigning to; {Structure-type} is the name of the Structure variables type and {field-name} is the name of the field in the Structure that you are assigning the data to. Retrieving a field value from a Structure requires a similar syntax:

119

Chapter 13
GetBuff From {Structure-variable} At {Structure-type}.{fieldname} To {variable}

where {Structure-variable} is the name of the Structure variable you are reading from; {Structure-type} is the name of the Structure variables type; {field-name} is the name of the field in the Structure that you are reading from and {variable} is the name of the variable that will receive the Structure fields value. Some examples of assigning and reading Structure field values are:
// Declare the Tree View item Type Type TV_ITEM Field TV_ITEM.mask as Field TV_ITEM.hItem as Field TV_ITEM.state as Field TV_ITEM.stateMask as Field TV_ITEM.pszText as Field TV_ITEM.cchTextMax as Field TV_ITEM.iImage as Field TV_ITEM.iSelectedImage as Field TV_ITEM.cChildren as Field TV_ITEM.lParam as End_Type // Declare a Tree View item variable UInteger iImage String sTreeViewItem ZeroType TV_ITEM To sTreeViewItem Put 1 To sTreeViewItem at TV_ITEM.State Put $FF To sTreeViewItem at TV_ITEM.StateMask GetBuff From sTreeViewItem at TV_ITEM.iImage To iImage

UInteger handle UInteger UInteger pointer UInteger UInteger UInteger UInteger UInteger

Advanced Data Types

120

Visual DataFlex Language Guide

Appendix A - Visual DataFlex Reserved Words


#EndHeader #Header #Include #Replace A Abort Abort_transaction Abs Acos Activate_view Add Address Addressof An And Append Append_output Ascii Asin Atan Attach Autopage Begin Begin_constraints Begin_transaction BigInt Boolean Break Broadcast Broadcast_focus Calc Calculate Call Call_driver Callback Case Cast CD_end_object CD_popup_object Center Chain Char Character Class Clear Close Close_input Close_output Cmdline Constrain Constrain_found_count Constrain_tests_count Constrained_clear Constrained_find Constraint_set Constraint_validate Contains Convert Copy_db Copy_records Copyfile Cos Create_field Create_index Currency Current_Object

Reserved Words

CurrentDateTime Date DateGetDay DateGetDayofWeek DateGetDayofYear DateGetHour DateGetMinute DateGetMonth DateGetSecond DateGetYear DateSetDay DateSetHour DateSetMinute DateSetMonth DateSetSecond DateSetYear Debug Decimal Declare_datafile Decrement Default_Currency_Mask

121

Appendix A
Default_Date_Mask Default_dbFloating_Menu_I D Default_Numeric_Mask Deferred_view Define Delegate Delete Delete_db Delete_field Delete_index End_transaction Entry_item Entry_name_item Enumeration_list Erasefile Err Errline Error Error_object_id Error_report Error_type Eval Exp External_Function External_Function16 Field Field_map Fieldindex File_exist Filenumber Fill_field Find Finderr Float For Format Formfeed Forward Forward_begin_construct Forward_end_construct Found From Function Function_return GbKenterNext Get Get_Address Get_argument_size Get_attribute Get_channel_position Get_channel_size Get_current_colors Get_current_directory Get_current_input_channel Get_current_lockcount Get_current_output_channel Get_cursor_visible Get_date_attribute Get_date_format Get_default_map_mode Get_directory Get_drive_directory Get_environment Get_field_value Get_file_mod_time Get_file_path Get_filelist Get_foreign_profile_string

Reserved Words

Dependent_item Derefc Derefdw Derefw Despool Direct_input Direct_output Directory Diskfree Else End End_class End_constraints End_Enumeration_list End_function End_item_group End_item_list End_object End_procedure

122

Visual DataFlex Language Guide

Get_icon_count Get_number_format Get_printer_setup Get_profile_string Get_program_key Get_registry_root Get_resource_name Get_transaction_retry Get_windows_directory Getbuff_string Getdskinfo GhiTimerManager GhoWorkSpace Global_Variable Gosub Gosub_Return Goto Graphics_adjust_coords Hi Iand If Ifchange Import_class_protocol Inactivate Include_resource Increment Ind Indicate Indicator

Insert Integer InvokeXML Ior Is_file_included IsDateValid Item_group Item_list Lasterr Left Length Linecount Load_def Load_driver Local Lock Log Logical Login Logout Loop Low Lowercase Ltrim Make_directory Make_file Make_temp_file Matches Max

MemCopy Memory MemSet Mid Min Mod Move Movedate Moveint Movenum Movereal Movestr Multiuser Name Name_item Name_items Name_object Not Num_arguments Number Object Of Offset_of_field On_item On_key On_name_item Open Or Output

Reserved Words

123

Appendix A

Output_aux_file Output_wrap Overstrike Pad Playwave Pos Print Print_wrap Procedure Procedure_return Property Put Put_string Random Read Read_block Read_dfini Read_hex Readln Real Register_function Register_object Register_procedure Register_resource Relate Remove Remove_directory Renamefile Repeat

Repeat_item Replace Replaces Reread Return Right Round Rtrim Runprogram Save Saverecord Self Send Seqeof Seqeol Set Set_app_profile_string Set_argument_size Set_attribute Set_channel_position Set_cursor_visible Set_date_attribute Set_default_map_mode Set_dfpath Set_field_value Set_file_mod_time Set_filelist Set_foreign_profile_string Set_profile_string

Set_registry_root Set_relate Set_resource_library Set_transaction_retry Short Show Showln Sin Size_of_field Sleep Sort SpanDays SpanHours SpanMinutes SpanSeconds SpanTotalDays SpanTotalHours SpanTotalMinutes SpanTotalSeconds Sqrt Start_ui Storec Storedw Storew String Strlen Strmark Structure_abort Structure_copy

Reserved Words

124

Visual DataFlex Language Guide

Structure_end Structure_start Subtotal Subtract Sysdate Sysdate4 System System_default_pageend System_default_pagefeed Tan Time TimeSpan To Total_resources Trim Type, End_Type UBigInt UChar UInteger Unload_driver Unlock Until Uppercase Use UShort Valid_drive Vconstrain Vfind While

Windowindex WinPrintId Winput WinQL_Report_Initialized Write Write_hex Writeln Zerofile Zerostring

Reserved Words

125

Visual DataFlex Language Guide

Appendix B - Naming Conventions


We recommend that you use Hungarian notation when naming identifiers in your Visual DataFlex applications. The Hungarian notation is a set of detailed guidelines for naming identifiers such as types and variables. The convention is widely used in many programming languages, especially in Windows programming. THE GOALS OF NOTATION To identify global variables; One common programming problem is the misuse of global variables. To identify class definitions; Naming conventions for classes serve two purposes: They explicitly identify an identifier as a class name, and they avoid naming clashes with objects and other variables or reserved words. To identify constants; Named constants need to be identified so that you can tell whether you are assigning a variable a value from another variable or from a named constant. To enhance readability.

Naming Conventions

BASE TYPES Hungarian notation works by prefixing identifiers with standardized codes. Each prefix to categorize the identifier according to its type and use. The first level of identifier prefixes identify the base types. The base type identifies the fundamental type of identifier that you are naming (e.g., is it a class, object, constant or variable). Hungarian notation prefixes each type of token to identify its base type as outlined in the following table: Base type Hungarian notation prefixes

PREFIX
c c_ g

MEANING
Class Constant Global variable

129

Appendix B PREFIX
o p

MEANING
Object Property Local variables (no-prefix)

All the prefixes, except C_ for constants, are in lowercase and placed before the rest of the token name. Note: The Local variable base type does not use a prefix.

Naming Conventions

Sub Type Subtypes go a step beyond the base type and describe the specific use of constants, global and local variables. Prefixes for Hungarian subtypes

PREFIX
b d h i n r s

MEANING
Boolean Date Handle Integer Number Real String

All the prefixes are in lowercase and placed before the rest of the token name but after the base type prefix. Examples of Hungarian notation

PREFIX
bFound

MEANING
A local Boolean variable.

130

Visual DataFlex Language Guide PREFIX


iCount giCount gsName cButton oCancelButton piCount psName C_PI

MEANING
A local Integer variable. A global Integer variable. A global String variable. A Class. An object. An integer property. A string property.

Naming Conventions

A constant.

131

Visual DataFlex Language Guide

C
VDF Specifications

Appendix C - Visual DataFlex Specifications


Features
Advanced Integrated Development Environment (IDE), with many built-in classes and completely customizable components and subclasses. New Code Explorer makes navigating, editing, and debugging programming code breeze. Now the Code Explorer can open any file. Jump to error editing of compiler errors. The industries leading report-writer, Seagate Crystal Reports for DataFlex is included. Integrated source-level debugger to help track down and fix problems. The latest developer servers and connectivity kits for client/server development including two-user licenses development and testing licenses for Pervasive.SQL and IBMs DB2 Universal Database. Improved and expanded wizards for building numerous programming components, including applications, views, and importing ActiveX controls. An enhanced Database Builder for building database tables and reusable DataDictionaries. Database Explorer for advanced raw data file viewing and editing. An explorer-style Help system interface, new Database Guide, and updated online help. Fully object-oriented 4th generation programming language (4GL). Data Access ODBC Connectivity Kit for accessing ODBC-compliant databases from Visual DataFlex (automatically installed with Visual DataFlex).

Requirements
Please refer to the Installation and Environment Guide to ascertain the requirements for memory, disk space, and operating system version that apply to your version of Visual DataFlex.

133

Appendix C

Platforms
Supported platforms are Windows 98, Windows NT 4 and Windows 2000. Please refer to the Installation and Environment Guide for more details.

Structure
Extended relational DBMS with data-independent utilities and command language.

VDF Specifications

Connectivity Kits
Visual DataFlex supports access to numerous different database formats through Connectivity Kits. Connectivity Kits are available for IBM DB2, Microsoft SQL, Pervasive.SQL and ODBC connectivity. Data Access Connectivity Kits allow for seamless conversion to and from, as well as direct access to, various different database formats without recompilation of applications. With the exception of the ODBC, all Connectivity Kits are direct drivers from VDF, and thus allow direct and fast access to the database.

Database Specifications (All Databases used with VDF)


TYPE
Maximum DBMS tables per file list Maximum file lists per application

DESCRIPTION
4095 Unlimited

DataFlex Database Record & Table Specifications


TYPE
Maximum data elements (fields) per table Maximum characters in physical table name (root name) Maximum characters in addressable table name (DataFlex name) Maximum table file size

DESCRIPTION
255 40 8 4 Gigabytes

134

Visual DataFlex Language Guide TYPE DESCRIPTION


Note: Refer to the Installation and Environment Guide for detailed information. Maximum records per table Maximum record size Data table type Numeric storage formats Numeric precision 16.7 Million (16,700,000) 16 Kilobytes (16,384 Bytes) Packed, fixed-length random access Packed BCD fixed point. Floating point Fixed point: 8 places after decimal point. Floating point: 16 significant digits. DECIMAL type adds 16.16 support. Numeric range Fixed: 9,999,999,999,999,999. 9999999999999999 with DECIMAL type. Floating: 1.0e306

VDF Specifications

DataFlex Database Index Specifications


TYPE
Maximum indexes per table Maximum segments per index Maximum index key length

DESCRIPTION
15 16 256 Bytes

DataFlex Database Field Specifications


TYPE
Maximum characters in field name Maximum data element (field) size Maximum size of ASCII field Maximum size of text field Size of date field

DESCRIPTION
15 16 Kilobytes (16,384 Bytes) 255 characters 16 Kilobytes (16,384 Bytes) 3 Bytes (Fixed)

135

Appendix C TYPE
Maximum size of numeric field

DESCRIPTION
99,999,999,999,999.99999999 to 9,999,999,999,999.99999999 (14.8 places) 16 Kilobytes (16,384 Bytes)

Maximum size of binary field

Application / Coding

VDF Specifications

Specifications for Visual DataFlex data types can be found in the Language Guide. Specifications for Visual DataFlex advanced data types and structured types can also be found in the Language Guide. All of the below specifications are per application. Each Visual DataFlex application can call other VDF and non-VDF applications, and even return to the same place in the code after doing so using the chain and runprogram commands.

TYPE
Maximum lines per program Maximum line length in Code Editor Maximum compilable statement length

DESCRIPTION
128 million (128,000,000) 255 characters 4095 characters (a statement exceeding 255 characters must be broken up into multiple lines of code, separated by a semicolon, which indicates a continuous statement). 2048 characters 10 files

Maximum custom error message length Maximum number of files that can be simultaneously opened for sequential file I/O Integer range Program file characteristics Maximum number of objects Maximum object messages Maximum number of classes

2,147,483,647 Protected source, semi-compiled 32,768 3,072 32,768

136

Visual DataFlex Language Guide TYPE


Maximum size of compiled program without symbols Maximum data tables open concurrently Types of arguments

DESCRIPTION
2 Gigabytes (2,147,483,648 Bytes) Memory limited only Text Strings Numeric fixed point Numeric floating point Integer Date (extended Julian)

VDF Specifications

Database Specifications (All Databases used with VDF)


TYPE
Maximum DBMS tables per file list Maximum file lists per application

DESCRIPTION
4095 Unlimited

DataFlex Database Record & Table Specifications


TYPE
Maximum data elements (fields) per table Maximum characters in physical table name (root name) Maximum characters in addressable table name (DataFlex name) Maximum table file size

DESCRIPTION
255 40 8 4 Gigabytes Note: Refer to the Installation and Environment Guide for detailed information.

Maximum records per table Maximum record size Data table type

16.7 Million (16,700,000) 16 Kilobytes (16,384 Bytes) Packed, fixed-length random access

137

Appendix C TYPE
Numeric storage formats Numeric precision

DESCRIPTION
Packed BCD fixed point. Floating point Fixed point: 8 places after decimal point. Floating point: 16 significant digits. DECIMAL type adds 16.16 support.

Numeric range

VDF Specifications

Fixed: 9,999,999,999,999,999. 9999999999999999 with DECIMAL type. Floating: 1.0e306

DataFlex Database Index Specifications


TYPE
Maximum indexes per table Maximum segments per index Maximum index key length

DESCRIPTION
15 16 256 Bytes

DataFlex Database Field Specifications


TYPE
Maximum characters in field name Maximum data element (field) size Maximum size of ASCII field Maximum size of text field Size of date field Maximum size of numeric field

DESCRIPTION
15 16 Kilobytes (16,384 Bytes) 255 characters 16 Kilobytes (16,384 Bytes) 3 Bytes (Fixed) 99,999,999,999,999.99999999 to 9,999,999,999,999.99999999 (14.8 places) 16 Kilobytes (16,384 Bytes)

Maximum size of binary field

138

Visual DataFlex Language Guide

Application / Coding
Specifications for Visual DataFlex data types can be found in the Language Guide. Specifications for Visual DataFlex advanced data types and structured types can also be found in the Language Guide. All of the below specifications are per application. Each Visual DataFlex application can call other VDF and non-VDF applications, and even return to the same place in the code after doing so using the chain and runprogram commands.

VDF Specifications

TYPE
Maximum lines per program Maximum line length in Code Editor Maximum compilable statement length

DESCRIPTION
128 million (128,000,000) 255 characters 4095 characters (a statement exceeding 255 characters must be broken up into multiple lines of code, separated by a semicolon, which indicates a continuous statement). 2048 characters 10 files

Maximum custom error message length Maximum number of files that can be simultaneously opened for sequential file I/O Integer range Program file characteristics Maximum number of objects Maximum object messages Maximum number of classes Maximum size of compiled program without symbols Maximum data tables open concurrently Types of arguments

2,147,483,647 Protected source, semi-compiled 32,768 3,072 32,768 2 Gigabytes (2,147,483,648 Bytes) Memory limited only Text Strings Numeric fixed point

139

Appendix C TYPE DESCRIPTION


Numeric floating point Integer Date (extended Julian)

Visual DataFlex Program File


When a Visual DataFlex 7 application is compiled, a file with a .vd7 extension is created (e.g., MyApplciation.vd7). This is the file that the Visual DataFlex executable program (dfrun.exe) executes when the application is run. To execute a Visual DataFlex application, simply double-click on the .vd7 file, and the appropriate entries in the Windows Registry associate the file with the correct executable program.

VDF Specifications

Argument Size
Visual DataFlex has a global argument size, which controls the maximum size a local string variable and a text database field can be addressed in an application. The default argument size in Visual DataFlex 7 is 32000 bytes. This is already larger than the maximum size of a DataFlex database record, but if you are using non-DataFlex databases or accessing sequential files in your application, you may need to increase the argument size. The maximum possible argument size is 2,000,000 (2 million) bytes. For performance reasons, you should keep the argument size as low as is needed for your application. You can use the get_Argument_Size command, to determine what the current argument size is and the set_Argument_Size command to increase the current argument size. Example
Procedure DoAdjustArgumentSize integer iArgSize get_Argument_Size to iArgSize if (ArgSize<64000) ; set_Argument_Size 64000 End_Procedure // DoAdjustArgumentSize

This example increases the current argument size to 64000 if it is less than 64000. For more information see, File Names & Extension Types and Logical Structure of a Database File in the Database Guide.

140

Visual DataFlex Language Guide


Visual DataFlex Data Types in the Language Guide. Creating a New File and Dictionary in the Database Builder Help book.

VDF Specifications

141

You might also like