Routine Type
It is possible to create a type that contains a routine ( Function or Shape ). A variable of this type can contain any routine with the correct signature ( parameter types and return type ).
This concept is easier to explain with a simple example.
Type SimpleFunct = Number(Number n); [= 1 =] Program() SimpleFunct trigfn = Sin; [= 2 =] Begin Output trigfn(30); [= 3 =] End;
The type declaration ( statement 1 ), defines a type "SimpleFunct" to be a function that takes a single numeric parameter and return a numeric value.
The variable declaration ( statement 2 ) creates a variable of this type, so the variable 'trigfn' can take any function that matches the signature. In this case we are initialising it to the built in function Sin.
In the Output code ( statement 3 ) you are calling the function that is stored in 'trigfn' - in this case Sin.
Advanced Example
The following example uses the planet symbol routines written in previous tutorials. This example illustrates the versatility of the mechanism. You can use Shape as well as functions. And you can use routine types as fields in a structure. The 'planet' field is a Shape routine. So following that field with a parameters list will invoke the particular Shape held within the field. Remember even if the parameter list is empty you still need the parentheses.
Type PlanetShape = Shape(Number size); Type PlanetRec = { Point posn, PlanetShape planet }; Type PlanetList = PlanetRec[]; Const PlanetList DemoList = [ {{50, 100}, MercurySymbol}, {{100, 100}, VenusSymbol}, {{150, 100}, EarthSymbol}, {{200, 100}, MarsSymbol} ]; Program( ) Begin Over DemoList As item Do item.planet(20) => item.posn; EndOver; End;type_routfn_1.grs
Parameter Attributes
Each parameter for a routine can have a Const or Ref attribute. There are rules governing how these are checked.
The Ref Attribute
If the Ref attribute is specified for a parameter in the type then the Ref attribute of the corresponding parameter in the routine being assigned to the variable of that function type must have a matching attribute.
The Const Attribute
If a parameter in a function type has the Const attribute the only routines with the corresponding parameter also set to constant may be assigned. If the type does not have the Const attribute then the corresponding parameter can be either Const or not.
Parameter Names
When calling a function using parameter names via a variable the compiler expect the names used in the type definition not the variable name used in the actual function definition.
Type TMyFunct = Number(Number parm1); Program( ) TMyFunct fn; Number res; Begin fn := TestFunct; res := fn(parm1 -> 42); End; Function Number TestFunct(Number a) Begin Return a + 1; End;
Parameter Defaults
When calling a routine via a routine variable the default parameters of the original routine are not accessible. You can however define default parameters in the type definition.
So the following function call will return 101 rather than 43.
Type TMyFunct = Number(Number parm1 = 100); Program( ) TMyFunct fn; Number res; Begin fn := TestFunct; res := fn(); End; Function Number TestFunct(Number a = 42) Begin Return a + 1; End;