Openhab 2.1 dynamic functions and map reference

Hello,
After upgrading from 2.0 to 2.1 (on openhabian image) I have a rule that having problem.
I’ve created a test case:

var java.util.Map<String, Boolean> t = newHashMap

val org.eclipse.xtext.xbase.lib.Procedures$Procedure2<SwitchItem,java.util.Map<String, Boolean>> doIt = [
SwitchItem r,
java.util.Map<String, Boolean> timers |
logInfo(“test”,"test1 on " + relayItem.name)

Boolean a = timers.getOrDefault(r)
if (a) {
    logInfo("test","test2")
    timers.put(r.name, true)
}

logInfo("test","test3")

]

rule “map function”
when
System started
then
logInfo(“test”,“test start”)
doIt.apply(girlsLight, t)
logInfo(“test”,“test finished”)
end

In my real rule I the map is null when it gets to the procedure.
In this example I see this error:

2017-06-29 23:50:50.808 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model ‘dyn.rules’, using it anyway:
This expression is not allowed in this context, since it doesn’t cause any side effects.
2017-06-29 23:50:50.941 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model ‘dyn.rules’
2017-06-29 23:50:56.921 [INFO ] [.eclipse.smarthome.model.script.test] - test start

I recall putting a true at the end of the lambda gave it something to return, to satisfy that error message.

@rossko57 is correct.

All lambdas have a return value.

The result of the last line executed in the lambda is what gets returned.

However, some methods do not return anything (i.e. they return a special type called void). The log Actions are this type of method.

So the error is essentially saying that your lambda is invalid because it doesn’t return anything.

Now I’ve not worked with Procedures$Procedure before, I usually work with Functions$Function. When working with Functions$Function, the stuff between the < > where you list the types of your arguments includes a final one that defines the types of the return.

So, for example, if I were to rewrite your lambda as a Functions$Function, and modify it so it returns a value, it would look something like:

import org.eclipse.xtext.xbase.Functions
import java.util.Map

val Functions$Function2<SwitchItem, Map<String, Boolean>, Boolean> doit = [ r, timers |
    logInfo("test", "test1 on " + r.name)

    val timer = timers.getOrDefault(r.name, false)
    if(!a) {
        logInfo("test", "test2")
        timers.put(r.name, true)
    }

    logInfo("test", "test3")
    true
]

Note I made some corrections to your rule which I assume are the result of your transcribing and simplifying a more complex rule here to simplify the rule. Some things to note:

  • if you imports you don’t need to use the fully qualified name for things like Functions and Map
  • if you specify the types in the < > is it redundant to specify them again when you declare the arguments between the [ and |
  • you can specify the types of the key and value in the Map using the < > as well which is good practice
  • you were missing the default in your getOrDefault call on the timers map
  • I assumed you meant r when you referenced “relayItem.name”
  • I assumed that you only wanted to go into the if clause when there was nothing in timers for r.
  • If you supply the types of the key and value in the Map, it is redundant to supply them for your a variable
  • you must declare the a variable with a var or a val even if you do use the redundant Boolean type

If you have a lambda where you want the return value in your caller you can do so like this:

val result = doIt.apply(girlsLight, t)
if(result) logInfo("Test", "Lambda returned true")
else logInfo("Test", "Lambda returned false")

Well procedure not need any parameter.
I’ve change it to function and still…
Now my problem it’s with the map:
2017-06-30 08:27:55.754 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model ‘dyn.rules’ has errors, therefore ignoring it: [3,1]: no viable alternative at input ‘val’

It configured like this:
val java.util.Map<String, Boolean> t = new HashMap<>
I’ve tried to set it with newHashMap and still the same behaviour…

same happen to me with another rule:
[WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model ‘lights_dynamic.rules’ has errors, therefore ignoring it: [9,1]: no viable alternative at input ‘var’
[12,1]: no viable alternative at input ‘var’
[18,1]: no viable alternative at input ‘val’

where the declaration is:
import java.util.Map
import java.util.HashMap

var Map<String, Timer> t1= new HashMap<>
var Map<String, Timer> timers = new HashMap<>
var Map<String, Boolean> tt = new HashMap<>

any ideas why the error message appear?

Thanks ahead

I wouldn’t think empty <> are very good? What happens if you specify types in there?

@rossko57 thanks, it focused me on the problem,

It looks like it does not recognize the Boolean.
Even after I added import to java.lang.Boolean

Any idea why?

Should be

val Map<KeyType, ValueType> t = newHashMap

Where KeyType and ValueType are the types of the key and value respectively.

The <> part must not be empty and must go on the Map part on the left side of the equals.

Like I said above, either a “val” or a “var” needs to be the first thing on any line that declares a variable.

Well now it is working but the function now being called.
Here is the new code (simpler):

import org.eclipse.xtext.xbase.Functions

val Function2<Integer, Integer, Boolean> autoOff = [
	Integer relayItem, Integer motionRelay | 
    logInfo("Test", "test")
    true
]

rule "map function"
when
    System started 
then
    logInfo("test","test start")
	autoOff.apply(1,2)
    logInfo("test","test finished")
end

Here are the logs:

2017-07-02 00:26:30.433 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'dyn.rules', using it anyway:
    The field Tmp_dynRules.autoOff refers to the missing type Object
2017-07-02 00:26:30.441 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'dyn.rules'
2017-07-02 00:26:36.135 [INFO ] [.eclipse.smarthome.model.script.test] - test start

what is the meaning of The field Tmp_dynRules.autoOff refers to the missing type Object

I would guess it does not know any object named autoOff.
The implication would be that the definition for autoOff has failed.
Is there a reason to use Function2 instead of Functions$Function2 ?

One line before I added import (sorry for my wrong edit… I’ve fix it now)

Is there a reason to use Function2 instead of Functions$Function2 ?

no, it is the same behaviour…

Correct me if I’m wrong, it looks like a bug in openhab 2.1

You must use Functions$Function2 like @rossko57 had mentioned twice.

In this case the import is not enough. There is a complicated explanation that I don’t have time for at the moment (I’ll come back if I remember).

The tl;Dr is that Function2 is a member of the class Functions and therefore cannot be referenced or imported independently.

@rlkoshak & @rossko57
Thank you!!!
It is working now!