Opened 9 years ago

Last modified 9 years ago

#3419 new defect

Function signatures for type safe function partial application

Reported by: Rüdiger Franke Owned by: Lennart Ochel
Priority: high Milestone: Future
Component: Code Generation Version: trunk
Keywords: Cc:

Description (last modified by Rüdiger Franke)

OpenModelica boxes arguments of functions that are passed as input to other functions. The actual types of the arguments appear to be only known during the boxing/unboxing operations. This hinders the generation of type safe code. The actual function signatures should be accessible from PARTEVALFUNCTION and FUNCTION_PTR (see SimCodeTV.mo).

See the following example:

partial function part
  input Real u;
  output Real y;
end part;

function func
  input Real u;
  input Real v;
  output Real y;
algorithm
  y := u + v;
end func;

function feval
  input part f;
  input Real u;
  output Real y;
algorithm
  y := f(u);
end feval;

model m
  input Real u = 0; // prevent presolving
  Real y = feval(function func(v = 2), u + 1);
end m;

When generating code for function feval, the signature of the input part should be accessible from the FUNCTION_PTR argument.

When generating code for model m, the signatures of the used function func and of the expected part should be accessible from PARTEVALFUNC.

So far only the types of the additional arguments of func (v in the example) can be derived from the expList contained in PARTEVALFUNC.

Change History (6)

comment:1 by Martin Sjölund, 9 years ago

It does not need to be there because the C runtime only passes void pointers. What code do you want to expand this to in C++?

comment:2 by Rüdiger Franke, 9 years ago

Description: modified (diff)

In the model m I want to create a kind of a closure that holds the additional argument v and provides an operator() that calls func:

    class _Closure_func
    {
      double &v;
     public:
      _Closure_func(double &v)
        : v(v)
      {}
      double operator()(double u) {
        return func(u, v);
      }
    };

This way the code for the function call in model m can look like:

  y = feval(_Closure_func(2.0), 1.0 + u);

The code for the function feval can look like

template <class _fnptr_part>
double FunctionPartialApplication_feval(_fnptr_part f, double u)
{
  double y;
  y = f(u);
  return y;
}

The problem is the missing type information for for u and v (at least for u) in PARTEVALFUNC when generating code the closure. The function itself can be implemented with template, because Modelica does not enforce inheritance of func from part. But a specific name containing the interface function part should be used -- this is not known in the current FUNTION_PTR.

Version 0, edited 9 years ago by Rüdiger Franke (next)

comment:3 by Martin Sjölund, 9 years ago

You can't depend on nominal typing (the name "part"), because the closure may be passed to other functions, and have a different name in these other functions. The type information of u and v are available in the PARTEVALFUNCTION call (unbox the types).

It may also be a recursive call, and I that might mess with the template calls as well.

comment:4 by Rüdiger Franke, 9 years ago

The nominal typing should work if the other functions use template arguments as well. But of course the intended functionality can also be achieved with inheritance and a virtual operator(), provided the type information is available during code generation.

Can you provide an example for unboxing the types?

(I only found out how to unbox expressions, like the expList in PARTEVALFUNC.)

comment:5 by Martin Sjölund, 9 years ago

The type is stored as simply T_BOXED(T_REAL). Types.unboxedType can be called.

comment:6 by Rüdiger Franke, 9 years ago

Thank you for the hint! Commit

https://github.com/OpenModelica/OMCompiler/commit/cd36c55594f634cc1f5735ad5b3ac498eaac20d3

exploits Types.unboxedType to generate the closure as in comment:2. This way arbitrary argument types should work now.

The remaining shortcoming is that only up to one function input per function works with the currently used unspecific template <class modelica_fnptr> (instead of _fnptr_part). This is why the name of the function part should be known in FUNCTION_PTR and in PARTEVALFUNC. How can this name be obtained?

Note: See TracTickets for help on using tickets.