Procedures and functions
Topics covered in this section:
It is possible to group sets of statements and declarations in the form of subroutines that, once defined, can be called several times during the execution of the model. There are two kinds of subroutines in Mosel, procedures and functions. Procedures are used in the place of statements (e.g. writeln("Hi!")) and functions as part of expressions (because a value is returned, e.g. round(12.3)). Procedures and functions may both receive arguments, define local data and call themselves recursively.
Definition
Defining a subroutine consists of describing its external properties (i.e. its name and arguments) and the actions to be performed when it is executed (i.e. the statements to perform). The general form of a procedure definition is:
procedure name_proc [(list_of_parms)] Proc_body end-procedure |
where name_proc is the name of the procedure and list_of_parms its list of formal parameters (if any). This list is composed of symbol declarations (cf. Section The declaration block) separated by commas. The only difference from usual declarations is that no constants or expressions are allowed, including in the indexing list of an array (for instance A=12 or t1:array(1..4) of real are not valid parameter declarations). The body of the procedure is the usual list of statements and declaration blocks except that no procedure or function definition can be included.
procedure myproc writeln("In myproc") end-procedure procedure withparams(a:array(r:range) of real, i,j:integer) writeln("I received: i=",i," j=",j) forall(n in r) writeln("a(",n,")=",a(n)) end-procedure declarations mytab:array(1..10) of real end-declarations myproc ! Call myproc withparams(mytab,23,67) ! Call withparams
The definition of a function is very similar to the one of a procedure:
function name_func [(List_of_params)]: Type Func_body end-function |
The only difference with a procedure is that the function type must be specified: it can be any type name except mpvar. Inside the body of a function, a special variable of the type of the function is automatically defined: returned. This variable is used as the return value of the function, it must therefore be assigned a value during the execution of the function.
function multiply_by_3(i:integer):integer returned:=i*3 end-function writeln("3*12=", multiply_by_3(12)) ! Call the function
Normally all statements of a subroutine are executed in sequence. It is however possible to interrupt the execution and return to the caller by using the special statement return.
Formal parameters: passing convention
Formal Parameters of basic types are passed by value and all other types are passed by reference. In practice, when a parameter is passed by value, the subroutine receives a copy of the information so, if the subroutine modifies this parameter, the effective parameter remains unchanged. But if a parameter is passed by reference, the subroutine receives the parameter itself. As a consequence, if the parameter is modified during the process of the subroutine, the effective parameter is also affected.
procedure alter(s:set of integer,i:integer) i+=1 s+={i} end-procedure gs:={1} gi:=5 alter(gs,gi) writeln(gs," ",gi) ! Displays: {1,6} 5
Local declarations
Several declaration blocks may be used in a subroutine and all identifiers declared are local to this subroutine. This means that all of these symbols exist only in the scope of the subroutine (i.e. between the declaration and the end-procedure or end-function statement) and all of the resource they use is released once the subroutine terminates its execution unless they are referenced outside of the routine (e.g. member of a set defined globally). As a consequence, active constraints (linctr that are not just linear expressions) declared inside a subroutine and the variables they employ are still effective after the termination of the subroutine (because they are part of the current problem) even if the symbols used to name the related objects are not defined any more. Note also that a local declaration may hide a global symbol.
declarations ! Global definition i,j:integer end-declarations procedure myproc declarations i:string ! This declaration hides the global symbol end-declarations i:="a string" ! Local 'i' j:=4 writeln("Inside of myproc, i=",i," j=",j) end-procedure i:=45 ! Global 'i' j:=10 myproc writeln("Outside of myproc, i=",i," j=",j)
This code extract displays:
Inside of myproc, i=a string j=4 Outside of myproc, i=45 j=4
Overloading
Mosel supports overloading of procedures and functions. One can define the same function several times with different sets of parameters and the compiler decides which subroutine to use depending on the parameter list. This also applies to predefined procedures and functions.
! Returns a randomly generated integer in the interval [1,limit] function random(limit:integer):integer returned:=round(.5+random*limit) ! Use the predefined ! 'random' function end-function
It is important to note that:
- a procedure cannot overload a function and vice versa;
- it is not possible to redefine any identifier; this rule also applies to procedures and functions. A subroutine definition can be used to overload another subroutine only if it differs for at least one parameter. This means, a difference in the type of the return value of a function is not sufficient.
Forward declaration
During the compilation phase of a source file, only symbols that have been previously declared can be used at any given point. If two procedures call themselves recursively (cross recursion), it is therefore necessary to be able to declare one of the two procedures in advance. Moreover, for the sake of clarity it is sometimes useful to group all procedure and function definitions at the end of the source file. A forward declaration is provided for these uses: it consists of stating only the header of a subroutine that will be defined later. The general form of a forward declaration is:
forward procedure Proc_name [(List_of_params)] or forward function Func_name [(List_of_params)]: Basic_type |
where the procedure or function Func_name will be defined later in the source file. Alternatively a subroutine can be declared by stating its header inside of a declarations block. Note that a forward declaration for which no actual definition can be found is considered as an error by Mosel.
forward function f2(x:integer):integer function f1(x:integer):integer returned:=x+if(x>0,f2(x-1),0) ! f1 needs to know f2 end-function function f2(x:integer):integer returned:=x+if(x>0,f1(x-1),0) ! f2 needs to know f1 end-function
Suffix notation
Functions which name begins with get and taking a single argument may be called using a suffix notation. This alternative syntax is constructed by appending to the variable name (the intended function parameter) a dot followed by the function name without its prefix get. For instance the call getsol(x) is the same as x.sol. The compiler performing internally the translation from the suffix notation to the usual function call notation, the two syntaxes are equivalent.
Similarly, calls to procedures which name begins with set and taking two arguments may be written as an assignment combined with a suffix notation. In this case the statement can be replaced by the variable name (the intended first procedure parameter) followed by a dot and the procedure name without its prefix set then the assignment sign := and the value corresponding to the second parameter. For instance the statement sethidden(ctl,true) can also be written ctl.hidden:=true. As for the other alternative notation, the compiler performs the rewriting internally and the two syntaxes are equivalent.
© 2001-2022 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.