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}

    {statement 2}

    …

    {statement n}

    [Function_Return {return-value}]

End_Function

Where:

Parameters

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 of the DataFlex simple types (Integer, Number, Real, etc.) as well as struct types and arrays.

By Reference parameters can also be declared. In this case the parameter's name must be preceded by the keyword "ByRef". When a parameter is passed by reference, the function has direct read/write access to the passed variable. For more information refer to Parameter Passing.

Return Value

Each function method must return a value. Execution of the method stops immediately after a Function_Return statement has been executed.

Refer to Declaring Procedure Set Methods for an example on declaring a function method.

Ambiguous Functions

When using functions and properties in DataFlex, the compiler does not know which object will actually handle the message. This is due to a combination of how OOP is implemented in DataFlex, the DataFlex language being weakly typed and message delegation. This is why the compiler won’t complain if you call a function on an object that does not have that function (this results in a runtime error). If a function with the same name is defined multiple times this can cause issues, especially if they have different return types. Calling these functions using the GET syntax this doesn’t lead to problems because GET doesn’t need to know the return type at compile time, it determines at runtime if a type conversion needs to be done.

However, accessing these functions using the expression syntax can lead to problems. When compiling an expression, the function return type determines which expression instructions are created. Different types are put on the expression stack in different ways and the rest of the expression assumes a specific type on the stack. The runtime will convert the result of the function to what it expects, and if that is an illegal conversion this triggers runtime errors.

So if the first function definition defines the return type as integer while the second implementation defines it as a string, the expression evaluator will still assume the outcome to be an integer resulting in a type conversion when expression is executed. If the actual data returned can not be converted, an error is declared. These errors can be hard to find because the initial definition can be far away from subsequent definitions. The first function might be defined in a library or even in the runtime.

The compiler does detect when a function is defined with the same name as another function but a different return type, and declares a compiler warning. The compiler also detects when one of these ambiguous functions is used.

For example:

Use UI

 

Object oFoo is a cObject

    Property Integer pDummyProp 0

 

    Function GetDummyScalar Returns Integer

        Function_Return 4

    End_Function   

End_Object

 

 

Object oBar is a cObject

    Property String pDummyProp ""

   

    Function GetDummyScalar Returns String

        Function_Return "X"

    End_Function

End_Object

 

Procedure Test

    String sVal

    Move (GetDummyScalar(oBar)) to  sVal

End_Procedure

 

Send Test

Inkey WindowIndex

The above example results in 3 warnings...