Passing records as parameter
Passing records by expansion (.*
notation)
All elements of a RECORD
structure can be passed by value to a function with the
dot star (.*
) notation.
record.*
parameter syntax is supported for backward compatibility.
Consider passing records by reference, or by value by specifying the record name only.When using the .*
notation as function parameter, the record is expanded: Each
member of the record structure is pushed on the stack. The receiving local variables in the function
must be defined with the same record structure as the caller.
For backward compatibility, the runtime system allows to call functions defined with the individual parameters matching the record members (or the other way around - calling a function with individual values that match the record parameter definition of the function). However, this is bad practice.
.*
notation like with legacy functions: The compiler will reject the code, if the complex parameters
types (records, arrays) do not match.In the next example, the func_r()
function is defined with a record parameter,
while the func_ab()
function is defined with individual integer and string
parameters:
MAIN
DEFINE rec RECORD
a INT,
b VARCHAR(50)
END RECORD
CALL func_r(rec.*)
CALL func_ab(rec.*) -- Bad practice!
CALL func_r(101, 'aaa') -- Bad practice!
END MAIN
-- Function defining a record like that in the caller
FUNCTION func_r(r)
DEFINE r RECORD
a INT,
b VARCHAR(50)
END RECORD
DISPLAY "func_r : ", r.*
END FUNCTION
-- Function defining two individual variables
FUNCTION func_ab(a, b)
DEFINE
a INT,
b VARCHAR(50)
DISPLAY "func_ab: ", a, b
END FUNCTION
Passing records by reference with INOUT
To pass records by reference, define a TYPE
with the RECORD
structure, and use this type in the parameter definition of the function, followed by the
INOUT
keyword.
The function must be known by the fglcomp compiler: It is not possible to use
this feature for linked functions. The function defining the INOUT
parameter must
be declared locally in the same module, or it must be defined in a module imported with IMPORT FGL
.
The function can then be invoked by specifying the record name as parameter.
TYPE CustRec RECORD
cust_id INTEGER,
cust_name VARCHAR(50)
END RECORD
MAIN
DEFINE r CustRec
CALL initialize_customer(r)
DISPLAY r.*
END MAIN
FUNCTION initialize_customer(r CustRec INOUT)
LET r.cust_id = 0
LET r.cust_name = "<undefined>"
END FUNCTION
See also the optimization topic Passing records by reference.
Passing records by value
.*
notation) to methods for
types:FUNCTION (c t_cust) setLastOrderId(o t_order)
LET c.last_order_id = o.order_id
END FUNCTION
util.JSON.stringify()
:IMPORT util
...
DEFINE rec RECORD
cust_id INTEGER,
cust_name VARCHAR(50)
END RECORD
...
CALL util.JSON.stringify( rec )
...
The record is not fully copied on the stack.
Passing records implicitly by reference to methods of built-in classes
util.JSON.parse()
, the record is implicitly passed by reference, and it can
be modified by the
method:IMPORT util
...
DEFINE rec RECORD
cust_id INTEGER,
cust_name VARCHAR(50)
END RECORD
...
CALL util.JSON.parse( '{"cust_id":2735, "cust_name":"McCarlson"}', rec )
...