Closures in Modelica

Modelica supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.

function intSeq
  output Function nextInt;
protected 
  Integer i(start=0);
algorithm 
  nextInt := function
    output Integer out;
  algorithm 
    i := i + 1;
    out := i;
  end function;
end intSeq;

function main
protected
  Function nextInt;
  Function newInts;
algorithm
  nextInt := intSeq();
  
  Modelica.Utilities.Streams.print(String(nextInt()));
  Modelica.Utilities.Streams.print(String(nextInt()));
  Modelica.Utilities.Streams.print(String(nextInt()));
  
  newInts := intSeq();
  Modelica.Utilities.Streams.print(String(newInts()));
end main;

This function intSeq returns another function, which we define anonymously in the body of intSeq. The returned function closes over the variable i to form a closure.

In the main function, we call intSeq, assigning the result (a function) to nextInt. This function value captures its own i value, which will be updated each time we call nextInt.

We can see the effect of the closure by calling nextInt a few times.

To confirm that the state is unique to that particular function, we create and test a new one.

To run this Modelica code, you would typically use a Modelica simulation environment. The output would be:

1
2
3
1

Note that Modelica is primarily used for modeling and simulation of physical systems, so this example is somewhat atypical. In a real-world scenario, you might use closures in Modelica for more domain-specific purposes, such as defining custom components or equations that maintain internal state.

The next feature we’ll look at is recursion, which is also supported in Modelica.