FUNCTION

<< Click to Display Table of Contents >>

Navigation:  Gekko User Manual > Gekko statements >

FUNCTION

Previous pageReturn to chapter overviewNext page

FUNCTION is used to define user-defined functions. Such user functions may return a variable (if you need to return multiple variables, consider returning a map). For a function that does not return anything (a stand-alone function), you may consider using a procedure instead (a procedure is essentially the same as a user function with no return value).

 

Note that all Gekko functions (both in-built and user-defined) implement so-called UFCS so that a function like for instance f(x, y) can be written as x.f(y), and f(x, y, z) can be written as x.f(y, z).

 

Libraries

It is possible to organize user-defined functions and procedures in libraries. These are basically just .zip-files that are loaded with the LIBRARY statement.

 

You may decorate a user function with a <>-option field containing an optional time period. User-defined functions allow optional parameters with default values, and the function may prompt (ask) the user about these parameters, if f?(...) is used instead of f(...), where f is the name of the function. See the LOCAL keyword if you need variables defined inside the function to be inaccessible/nonexisting outside the function.

 


 

Syntax

 

function type funcname(<date t1, date t2>, type1 var1 label1 = default1, type2 var2 label2 = default2, ...);
 expressions... ;
end;

 

Unless the return type is void, the function body must contain at least one RETURN statement, returning a variable.

 

t1, t2

(Optional). You may state optional time period parameters inside <>-brackets, for instance function series f(<date %t1, date %t2>, series x); after which %t1 and %t2 are assigned to for instance 2020 and 2030 in the call f(<2020 2030>, z). If the function is called without <>-brackets, for instance f(z) , the parameters %t1 and %t2 are assigned to the local/global time period instead. Using a <>-brackets in a function call does not in itself change the local time period inside the function: use for instance the BLOCK structure to do that. See examples.

type1, ...

Types of incoming and outgoing variables: series, val, date, string, list, map, matrix. You may also use the special name type for parameters, which behaves 100% as a string inside the function, but where the single quotes are omitted when calling the function from outside (the shorter call f(y) is used instead of f('y')).

 

If the function does not return anything, void can be used as type.

var1, ...

The parameters/variables/expressions

label1, ...

(Optional). A label for the parameter, used if the function is promting (called with f?(...)). See more about prompting below.

default1, ...

(Optional). A default value for the parameter. If the parameter is omitted, the default value is used. If the function is asked to prompt (called with f?(...)) and the parameter is omitted, the default value is shown in the dialog box. In the dialog box, Enter or Escape will return the default value, and fire up the next dialog box (for the next optional parameter). If a ; is entered in the dialog box, all the remaining parameters attain their default values, and no more dialog boxes are shown. For string input, the use of quotes (') in the input box is optional. At the moment, only val, date and string types can be used for prompting input boxes.

funcname

The function name

body

The function body, that is, the statements to be performed. Use RETURN to return a variable. If several variables need to be returned, use a map or list to bundle them.

 

Tip: if you need to stop execution at a specific point/line to inspect variables etc., try inserting a STOP statement. This will abort from all called program files/procedures/functions, without executing anything more after the STOP (this is not the case regarding RETURN). Therefore, STOP can be practical for debugging, etc.

 


 

Example

 

Value examples, including multiple return values

 

The function sq() below returns the input value squared.

 

function val sq(val %x); 
  return %x*%x; 
end; 
//--------------
%= sq(4);
%= sq(sq(4));

 

The example will produce %= 16 and %= 256 (the function calls may be nested).

 

Multiple variables may be returned, using a collection like for instance a map:

 

function map f(val %x, val %y); 
  return (%sum = %+ %y, %product = %* %y); //see definition of a map
end; 
//----------------------------
#= f(3, 7);
prt #m.%sum, #m.%product;  //10, 21

 

 

Date example

 

function date add3(date %d); 
  return %+ 3; 
end; 
//------------------------------
%d3 = add3(2000q3);
prt %d3;  //2001q2

 

 

String example

 

function string f(string %x); 
  return %+ 'shine'; 
end; 
//----------------------
%= f('sun');
prt %y;  //'sunshine'

 

If you prefer to omit the quotes when calling the function (that is, f(sun) instead of f('sun'), you may use the name type:

 

function string f(name %x); 
  return %+ 'shine';  //%x behaves completely like a string 
end; 
//----------------------
%= f(sun);
prt %y;  //'sunshine'

 

 

List example

 

function val ncommon(list #x, list #y); 
  #temp = intersect(#x, #y);
  return #temp.len();
end; 
//----------------------
#m1 = x1, x2, x3, x4;
#m2 = x2, x4, x5, x6;
%= ncommon(#m1, #m2);
prt %v;  //2 common elements

 

 

Series example

 

function series idx(series x, date %d); 
  return x/x[%d]; 
end; 
//--------------------------------------
time 2000 2010;
x1 = 10, 11, 12, 13, 11, 14, 16, 17, 15, 19, 20;
prt x1, idx(x1, 2002), idx(x1, 2008);  //index 2002=1 and 2008=1

 

The function idx() provides indexed values.

 

 

Stand-alone function call example (void type)

 

function void f(val %x1, val %x2, val %x3); 
  tell 'Sum is: ' + (%x1 + %x2 + %x3);
end; 
//-----------------------------------
f(1, -2, 3);  //result: 'Sum is: 2'. This is similar to a procedure call

              //                     like "f 1 -2 3;" but without the 

              //                     problem of this being interpreted as

              //                     "f (1-2) 3;", or "f -1 3;".

 

 

Combined example

 

function void load(string %n, string %label, date %d1, date %d2, val %v);
  create {%n};  //must use {...}-braces to use as name.
  doc {%n} label = %label;
  {%n} <%d1 %d2> = %v;
  return;
end;
//-----------------------------------
load('extra1', 'Helper variable', 1980, 2020, 100);
load('vat', 'VAT rate', 1980, 2020, 0.25);
disp extra1, vat;

 

The load() function will create the two timeseries extra1 and vat, both with labels, and values 100 and 0.25, respectively. Since the function does not return any variable, you may use a procedure instead.

 

 

Local period example

 

function series f(<date %t1, date %t2>); 
  block time %t1 %t2; 
    y = 100; 
  end; 
  return y; //return statement after the block ends
end;
 
time 2001 2001;
z1 <2002 2002> = f();             //z1 will be 100 in 2002
z2 <2002 2002> = f(<2003 2003>);  //z2 will be 100 in 2003
<2001 2003 n> z1, z2;
 
// Result:
//                   z1             z2 
//  2001              M              M 
//  2002       100.0000              M 
//  2003              M       100.0000 

 

In the z1 statement, it is seen how the local period <2002 2002> is used inside the f() function, by means of a BLOCK using the arguments %t1 and %t2. The f() function itself is not called with time period, and since the time period is absent in the function call, %t1 and %t2 are assigned to the local period set outside of the f() function.

 

The z2 statement illustrates a call of f() where a time period is present inside the f() function. This overrules the local time period 2002-2002.

 

 

Promt and default values example

 

Gekko user-defined functions allow default values, and prompting regarding these.

 

function val f(val %x1, val %x2 'parameter 2' = 1, val %x3 'parameter 3' = 2); 
  return 10000 * %x1 + 100 * %x2 + %x3; 
end;
%y1 = f(9, 3, 4); //--> 90304
%y2 = f(9, 3);    //--> 90302
%y3 = f(9);       //--> 90102
%y4 = f?(9, 3);   //enter 5 into the dialog box --> 90305
%y5 = f?(9);      //enter 6 and 7 into the dialog boxes --> 90607
%y6 = f?(9);      //enter 6 and ';' into the dialog box --> 90602
mem;

 

Beware that f() or f?() will fail with an error, since the first parameter is required. As shown regarding the last function call, you may terminate a sequence of input boxes with ;, which means the default values are used for the current and following parameters. Pressing Enter or Escape returns the default value, and opens up the next input box. For prompt input, only the variable types val, date, string and name are supported at the moment (for name type, use for instance ... , name %x2 'parameter 2' = 'x', ...).


 

Note

 

See also PROCEDURE. A procedure can be thought of as a function without return values. Procedures and user functions do not live in databanks, and are hence not affected by CLEAR, CLOSE, READ, etc., but are removed with RESTART or RESET.

 

If a function is defined without <>-brackets to indicate time, it may still be called with <>-brackets. In that case, the time period inside the brackets is just ignored. Note that multiple return values can be handled with maps.

 

You may at most use 14 arguments, else use maps to bundle incoming arguments. Per default, all arguments are passed by value, not by reference (cf. option system clone). This means that functions cannot have so-called side-effects on the incoming arguments. Maps can be practical for bundling output variables.

 

It is planned to introduce the type namelist in addition to the name type, so that an argument like (a, b, c) can mean ('a', 'b', 'c') internally.

 


 

Related statements

 

LIBRARY, LOCAL, PROCEDURE, RUN