User Tools

Site Tools


prototype_parameter_lists.htm
Navigation:  Language Reference > 2 - Program Source Code Format > PROCEDURE Prototypes >====== Prototype Parameter Lists ====== Previous pageReturn to chapter overviewNext page

Topics in this help section:

General Syntax

Value Parameters

Variable Parameters

Passing Arrays

Parameters of Unspecified Data Type

Entity Parameters

Procedure Parameters

Passing Named GROUPs, QUEUEs, and CLASSes

General Syntax

[CONST] [REF] type [ label ]

<;[CONST] [REF] type [ label ] >

type [ label ] = default

blk2blue.jpg

CONST An optional qualifier for the parameter which is valid only on a variable-parameter. This means that the parameter being passed by address may not be updated in the procedure. It is treated as if it were a constant value.
REFNewCNet.jpg The REF keyword is added to Clarion# to provide compatibility with other .NET languages. It's used to mark a parameter as “passed by reference”. The REF keyword can be used before the type name in the parameter declaration.
type The data type of the parameter. This may be a value-parameter, variable-parameter, array, unspecified data type, entity, procedure-parameter, or a named GROUP, QUEUE, or CLASS.
label An optional documentary label for the parameter. This label is not required and is placed in the prototype for documentation purposes only.
<; > Angle brackets indicate the parameter is omittable. The OMITTED procedure detects the omission. All parameter types can be omitted.
= default A default value indicates the numeric parameter is omittable, and if omitted, the default value is passed. The OMITTED procedure will not detect the omission–a value is passed. Valid only on simple numeric types.

The parameter list in a PROCEDURE prototype is a comma-delimited list of the data types to pass to the PROCEDURE. The entire parameter list is enclosed in the parentheses following the PROCEDURE keyword (or the name). Each parameter's type may be followed by a space then a valid Clarion label for the parameter (which is ignored by the compiler and only documents the purpose of the parameter). Each numeric value-parameter (passed by value) may also include an assignment of a constant value to the type (or the documentary label, if present) that defines the default value to pass if the parameter is omitted.

Any parameter that may be omitted when the PROCEDURE is called must be included in the prototype's parameter list and enclosed in angle brackets ( <; > ) unless a default value is defined for the parameter. The OMITTED procedure allows you to test for unpassed parameters at runtime (except those parameters which have a default value).

Example:

MAP

 MODULE('Test')

MyProc1 PROCEDURE(LONG)                     !LONG value-parameter

MyProc2 PROCEDURE(<;LONG>)                   !Omittable LONG value-parameter

MyProc3 PROCEDURE(LONG=23)                  !Passes 23 if omitted

MyProc4 PROCEDURE(LONG Count, REAL Sum)     !LONG passing a Count and REAL passing a Sum

MyProc5 PROCEDURE(LONG Count=1, REAL Sum=0) !Count defaults to 1 and Sum to 0

 END

END

See Also:

MAP

MEMBER

MODULE

PROCEDURE

CLASS

REF

Value-parameters

Value-parameters are “passed by value.” A copy of the variable passed in the parameter list of the “calling” PROCEDURE is used in the “called” PROCEDURE. The “called” PROCEDURE cannot change the value of the variable passed to it by the “caller.” Simple assignment data conversion rules apply; Value-parameters actually passed are converted to the data type in the PROCEDURE prototype. Valid value-parameters are:

BYTE SHORT USHORT LONG ULONG SREAL REAL DATE TIME STRING

Example:

MAP

 MODULE('Test')

MyProc1 PROCEDURE(LONG)                       !LONG value-parameter

MyProc2 PROCEDURE(<;LONG>)                     !Omittable LONG value-parameter

MyProc3 PROCEDURE(LONG=23)                    !Passes 23 if omitted

MyProc4 PROCEDURE(LONG Count, REAL Sum)       !LONG passing a Count and REAL passing a Sum

MyProc5 PROCEDURE(LONG Count=1, REAL Sum=0)   !Count defaults to 1 and Sum to 0

 END

 MODULE('Party3.Obj')    

Func48 PROCEDURE(REAL),REAL,PASCAL            !PASCAL calling convention

Func49 PROCEDURE(SREAL),REAL,C,NAME('_func49')!C convention and external function name

 END

END

Variable-parameters

Variable-parameters are “passed by address.” A variable passed by address has only one memory address. Changing the value of the variable in the “called” PROCEDURE also changes its value in the “caller.” Variable-parameters are listed by data type with a leading asterisk (*) in the PROCEDURE prototype in the MAP. Valid variable-parameters are:

*BYTE *SHORT *USHORT *LONG *ULONG *SREAL *REAL *BFLOAT4 *BFLOAT8
*DECIMAL *PDECIMAL *DATE *TIME *STRING *PSTRING *CSTRING *GROUP *USTRING
*BSTRING *INT64 *UINT64 *VARIANT

Example:

MAP

 MODULE('Test')

MyProc2 PROCEDURE(<;*LONG>)               !Omittable LONG variable-parameter

MyFunc1 PROCEDURE(*SREAL),REAL,C         !SREAL variable-parameter, REAL return, C call conv

MyProc6 PROCEDURE(CONST *CSTRING Value)  !Value retains a constant value in procedure

 END

 MODULE('Party3.Obj')    

Func4  PROCEDURE(*CSTRING),REAL,C,RAW    !Pass CSTRING address-only to C function

Func47 PROCEDURE(*CSTRING),CSTRING,C,RAW !Returns pointer to a CSTRING

 END

END

Passing Arrays

To pass an entire array as a parameter, the prototype must declare the array's data type as a Variable-parameter (“passed by address”) with an empty subscript list. If the array has more than one dimension, commas (as position holders) must indicate the number of dimensions in the array. The calling statement must pass the entire array to the PROCEDURE, not just one element.

Example:

MAP

MainProc PROCEDURE

AddCount PROCEDURE(*LONG[,] Total,*LONG[,] Current)  !Passing two 2-dimensional arrays

END

CODE

MainProc                                            !Call first procedure

MainProc PROCEDURE

TotalCount LONG,DIM(10,10)

CurrentCnt LONG,DIM(10,10)

CODE

AddCount(TotalCount,CurrentCnt)                     !Call the procedure passing the arrays

AddCount PROCEDURE(*LONG[,] Total,*LONG[,] Current)  !Procedure expects two arrays

CODE

LOOP I# = 1 TO MAXIMUM(Total,1)                     !Loop through first subscript

 LOOP J# = 1 TO MAXIMUM(Total,2)                    !Loop through second subscript

  Total[I#,J#] += Current[I#,J#]                    !increment TotalCount from CurrentCnt

 END

END

CLEAR(Current)                                      !Clear CurrentCnt array

Parameters of Unspecified Data Type

You can write general purpose procedures which perform operations on passed parameters where the exact data type of the parameter may vary from one call to the next by using untyped value-parameters and untyped variable-parameters. These are polymorphic parameters; they may become any other simple data type depending upon the data type passed to the procedure.

Untyped value-parameters are represented in the prototype with a question mark (?). When the procedure executes, the parameter is dynamically typed and acts as a data object of the base type (LONG, DECIMAL, STRING, or REAL) of the passed variable, or the base type of whatever it was last assigned. This means that the “assumed” data type of the parameter can change within the PROCEDURE, allowing it to be treated as any data type.

An untyped value-parameter is “passed by value” to the PROCEDURE and its assumed data type is handled by Clarion's automatic Data Conversion Rules. Data types which may be passed as untyped value-parameters:

BYTE SHORT USHORT LONG ULONG SREAL
REAL BFLOAT4 BFLOAT8 DECIMAL PDECIMAL DATE
TIME STRING PSTRING CSTRING USTRING BSTRING
GROUP(treated as a STRING) Untyped value-parameter(?) Untyped Variable-parameter (*?)

The RAW attribute is valid for use if the untyped value-parameter (?) is being passed to external library functions written in other languages than Clarion. This converts the data to a LONG then passes the data as a C/C++ “void *” parameter (which eliminates “type inconsistency” warnings).

Untyped variable-parameters are represented in the PROCEDURE prototype with an asterisk and a question mark (*?). Within the procedure, the parameter acts as a data object of the type of the variable passed in at runtime. This means the data type of the parameter is fixed during the execution of the PROCEDURE.

An untyped variable-parameter is “passed by address” to the PROCEDURE. Therefore, any changes made to the passed parameter within the PROCEDURE are made directly to the variable which was passed in. This allows you to write polymorphic procedures.

Within a procedure which receives an untyped variable-parameter, it is not safe to make any assumptions about the data type coming in. The danger of making assumptions is the possiblity of assigning an out-of-range value which the variable's actual data type cannot handle. If this happens, the result may be disastrously different from that expected. See Also: ANYANY (any simple data type)

Data types which may be passed as untyped variable-parameters:

BYTE SHORT USHORT LONG ULONG SREAL REAL BFLOAT4
BFLOAT8 DECIMAL PDECIMAL DATE TIME STRING PSTRING CSTRING
Untyped variable-parameter (*?) USTRING BSTRING

The RAW attribute is valid for use if the untyped variable-parameter (*?) is being passed to external library functions written in other languages than Clarion. This has the same effect as passing a C or C++ “void *” parameter.

Arrays may not be passed as either kind of untyped parameter.

Example:

PROGRAM

MAP

Proc1 PROCEDURE(?)          !Untyped value-parameter

Proc2 PROCEDURE(*?)         !Untyped variable-parameter

Proc3 PROCEDURE(*?)         !Untyped variable-parameter (set to crash)

Max   PROCEDURE(?,?),?      !Procedure returning Untyped value-parameter

END

GlobalVar1  BYTE(3)         !BYTE initialized to 3

GlobalVar2  DECIMAL(8,2,3)

GlobalVar3  DECIMAL(8,1,3)

MaxInteger  LONG

MaxString   STRING(255)

MaxFloat    REAL

CODE

Proc1(GlobalVar1)          !Pass in a BYTE, value is 3

Proc2(GlobalVar2)          !Pass it a DECIMAL(8,2), value is 3.00 - it prints 3.33

Proc2(GlobalVar3)          !Pass it a DECIMAL(8,1), value is 3.0 - it prints 3.3

Proc3(GlobalVar1)          !Pass it a BYTE and watch it crash

MaxInteger = Max(1,5)      !Max procedure returns the 5

MaxString = Max('Z','A')   !Max procedure returns the 'Z'

MaxFloat = Max(1.3,1.25)   !Max procedure returns the 1.3

Proc1 PROCEDURE(? ValueParm)

CODE                       !ValueParm starts at 3 and is a LONG

ValueParm = ValueParm &amp; ValueParm  !Now Contains '33' and is a STRING

ValueParm = ValueParm / 10         !Now Contains 3.3 and is a REAL

Proc2 PROCEDURE(*? VariableParm)

CODE

VariableParm = 10 / 3              !Assign 3.33333333… to passed variable

Proc3 PROCEDURE(*? VariableParm)

CODE

LOOP

 IF VariableParm >= 256 THEN BREAK. !If passed a BYTE, BREAK will never happen

 VariableParm += 10

END

Max PROCEDURE(Val1,Val2)            !Find the larger of two passed values

CODE

IF Val1 > Val2                     !Check first value against second

 RETURN(Val1)                      ! return first, if largest

ELSE                               !otherwise

 RETURN(Val2)                      ! return the second

END

See Also:

MAP

MEMBER

MODULE

PROCEDURE

CLASS

Entity-parameters

Entity-parameters pass the name of a data structure to the “called” PROCEDURE. Passing the entity allows the “called” PROCEDURE to use those Clarion commands that require the label of the structure as a parameter. Entity-parameters are listed by entity type in the PROCEDURE prototype in the MAP. Entity-parameters are always “passed by address.” Valid entity-parameters are:

FILE VIEW KEY INDEX QUEUE WINDOW REPORT BLOB

A REPORT can be passed as the parameter to a procedure prototyped to receive a WINDOW, since internally they use the same passing structure.

Example:

MAP

 MODULE('Test')

MyFunc2  PROCEDURE(FILE),STRING      !FILE entity-parameter, returning a STRING

ProcType PROCEDURE(FILE),TYPE        !Procedure-parameter type definition

MyFunc4  PROCEDURE(FILE),STRING,PROC !May be called as a procedure without warnings

MyProc6  PROCEDURE(FILE),PRIVATE     !May only be called by other procs in TEST.CLW

 END

END

Procedure-parameters

Procedure-parameters pass the name of another PROCEDURE to the “called” PROCEDURE. Procedure-parameters are listed by the name of a prototype of the same type in the PROCEDURE prototype in the MAP (which may or may not have the TYPE attribute). When called in executable code, the “called” PROCEDURE must be passed the name of a PROCEDURE whose prototype is exactly the same as the procedure named in the “called” procedure's prototype.

Each parameter in the list may be followed by a valid Clarion label which is completely ignored by the compiler. This label is used only to document the parameter to make the prototype more readable, or to duplicate the PROCEDURE definition statement. Each passed parameter's definition may also include the assignment of a constant value to the data type (or the documentary label, if present) that defines the default value to pass if the parameter is omitted.

Example:

MAP

 MODULE('Test')

ProcType PROCEDURE(FILE),TYPE       !Procedure-parameter type definition

MyFunc3  PROCEDURE(ProcType),STRING !ProcType procedure-parameter, returning a STRING,

 END                               !must be passed a procedure that takes a FILE

END                                !as a parameter

Passing Named GROUPs, QUEUEs, and CLASSes

Passing a GROUP as a Variable-Parameter, or a QUEUE as an Entity-Parameter, to a PROCEDURE does not allow you to reference the component fields within the structure in the receiving PROCEDURE . You can alternatively pass a “named” GROUP or QUEUE to achieve this. You may also name a CLASS in the same manner to allow the receiving procedure to access the public data members and methods of the CLASS.

To reference the component fields within the structure, place the label of a GROUP, QUEUE, or CLASS structure in the receiving PROCEDURE's prototype parameter list as the data type for the parameter. This passes the parameter “by address” and allows the receiving procedure to reference the component fields of the structure (and the public methods of a CLASS pass in this manner).

The data actually passed as the parameter must always have a similar structure (defined with the same data types) for its component fields. The GROUP or QUEUE actually passed can be a “superset” of the named parameter, as long as the first fields in the “superset” group are the same as the GROUP or QUEUE named in the prototype. The actually passed CLASS object can also be a derived class of the CLASS named in the prototype. The “extra” fields in the passed GROUP, QUEUE, or CLASS are not available for use in the receiving procedure.

The GROUP, QUEUE, or CLASS named in the parameter list does not need to have the TYPE attribute, and does not have to be declared before the procedure's prototype, but it must be declared before the PROCEDURE that will receive the parameter is called. This is the only instance in the Clarion language where the compiler allows such a “forward reference.”

Use Field Qualification syntax to reference the members of the passed group in the receiving procedure (LocalName.MemberName). The member fields of the structure are referenced by the labels given them in the group named as the data type in the prototype–not the labels of the fields in the structure actually passed in. This allows the receiving procedure to be completely generic, regardless of what actual data structure is passed to it.

Example:

  PROGRAM

  MAP

MyProc PROCEDURE

AddQue PROCEDURE(PassGroup PassedGroup, NameQue PassedQue)

  END          !AddQue receives a GROUP defined like PassGroup and

               ! a QUEUE defined like NameQue

PassGroup  GROUP,TYPE   !Type definition – no memory allocated

F1          STRING(20)  !  GROUP with 2 STRING(20) fields

F2          STRING(20)

          END    

NameGroup  GROUP        !Name group

First       STRING(20)  !first name

Last        STRING(20)  !last name

Company     STRING(30)  !This extra field is not available to the receiving

          END          !procedure (AddQue) since PassGroup only has two fields

NameQue   QUEUE,TYPE    !Name Queue, Type definition – no memory allocated

First      STRING(20)

Last      STRING(20)

      END

CODE

MyProc

MyProc   PROCEDURE

LocalQue  NameQue       !Local Name Queue, declared exactly the same as NameQue

CODE

NameGroup.First = 'Fred'

NameGroup.Last = 'Flintstone'

AddQue(NameGroup,LocalQue)          !Pass NameGroup and LocalQue to AddQue procedure

NameGroup.First = 'Barney'

NameGroup.Last = 'Rubble'

AddQue(NameGroup,LocalQue)

NameGroup.First = 'George'

NameGroup.Last = 'O''Jungle'

AddQue(NameGroup,LocalQue)

LOOP X# = 1 TO RECORDS(LocalQue)    !Look at what's in the LocalQue now

 GET(LocalQue,X#)

 MESSAGE(CLIP(LocalQue.First) &amp; ' ' &amp; LocalQue.Last)

END

AddQue  PROCEDURE(PassGroup PassedGroup, NameQue PassedQue)

CODE

PassedQue.First = PassedGroup.F1    !Effectively:  LocalQue.First = NameGroup.First

PassedQue.Last  = PassedGroup.F2    !Effectively:  LocalQue.Last = NameGroup.Last

ADD(PassedQue)                      !Add an entry into the PassedQue (LocalQue)

ASSERT(NOT ERRORCODE())

See Also:

MAP

MEMBER

MODULE

PROCEDURE

CLASS

prototype_parameter_lists.htm.txt · Last modified: 2021/04/15 15:57 (external edit)