Rules scripting - from a function to call another function

Hi,
I started to introduce functions to my rules to make the code easier to maintain, however I encountered a small issue: it looks like inside a function I cannot call another function, if I do so I receive an error like “cannot invoke method public abstract java.lang.Object org.eclipse.xtext.xbase.lib.Functions$Function2.apply(java.lang.Object,java.lang.Object) on null”. I assume it’s because the other function was not initialised before the caller function is initialised (even though I have the caller function definition after in rules). Is it not possible to make it work or what are my alternatives?
An example of the function:

val findBestChargingHour = [ int fromHour, int toHour, int numOfHours |
    var int bestHour = -1
    var double lowestAvgPrice = 999
    for (var hour = fromHour; hour<= (toHour - numOfHours); hour++) {
        var double avgPrice = calculateAvgElPrice.apply(hour, numOfHours)
        if (avgPrice < lowestAvgPrice) {
            lowestAvgPrice = avgPrice
            bestHour = hour
        }
    }
    new Pair<Integer, Double>(bestHour, lowestAvgPrice)
]

calculateAvgElPrice.apply call fails every time.

Down this path lies only misery with Rules DSL. This might be a sign it’s time to move to a new language, something with better support for this sort of thing like everything else but Rules DSL (even Blockly).

You can but you have to pass the other function in as an argument to the calling function.

When you create a lambda it inherits the context as it exists when it’s declared. That’s why when you createTimer or do a forEach you can reference variables defined in the rule inside the lambda without passing them as arguments.

When a lambda is declared globally, there is no context to inherit. So global lambdas cannot see or use anything that isn’t passed to them as an argument, including other globally defined variables (i.e. other global lambdas).

Oh, and there is a limit of only six arguments allowed for a lambda (maybe it’s seven).

Hi Rich, thank you for your reply!

How can I do this? The function doesn’t seem to have a type, and I need to declare a type for all the parameters.

If it returns something it’s of type Functions$FunctionX where X is the number of arguments it takes.

If there is no return value is Procedure$ProcedureX, again replace x with the number of arguments.

And you are not required to specify the type of the arguments to a function/procedure. But it’s all our nothing. Either none of them are defined or all of them are defined. Unless something had changed in the years since I last messed with them.

And everything is an Object so you can default to that if you need to, though you might need to cast inside the lambda to use it

1 Like

Thanks a lot!