[SOLVED] How previousState implicit variable works?

Hi, guys

I don’t understand why this code works:

rule "A presence sensor updated"
when
        Item gnuTest_Counter changed
then
    logInfo("Test previousState", triggeringItem.name + previousState )
end

producing:
2019-02-22 12:38:12.698 [INFO ] [home.model.script.Test previousState] - gnuTest_Counter1

… while this does not work:

rule "A presence sensor updated"
when
        Item gnuTest_Counter changed
then
    logInfo("Test previousState", triggeringItem.state + previousState ) 	
end

error (at event execution time…):
2019-02-22 12:41:52.379 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘A presence sensor updated’: An error occurred during the script execution: Could not invoke method: org.eclipse.xtext.xbase.lib.ObjectExtensions.operator_plus(java.lang.Object,java.lang.String) on instance: null

… just like this does not work:

rule "A presence sensor updated"
when
        Item gnuTest_Counter changed
then
    logInfo("Test previousState", previousState )
end

error (at parsing time…):
2019-02-22 12:42:59.895 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘A presence sensor updated’: An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.LogAction.logInfo(java.lang.String,java.lang.String,java.lang.Object[]) on instance: null

Regards.

Define “does not work”.

If you use Visual Studio Code with the OH extension, you would see the non-working cases flagged with an error: Type mismatch: cannot convert from State to String.
The non-working examples will probably work when you use triggeringItem.state.toString and previousState.toString.

1 Like

Good eye.

OK, here is what is going on. The Rules DSL is what we call a weakly typed language. This means it figures out the proper type for variables and Object at runtime instead of at compile time.

But, the Rules DSL is not particularly good at this. This usually causes problems when building Strings or trying to do math with Numbers.

The first one works because triggeringItem.name is a String, so the Rules DSL is able to determine that you are building a String. So it knows that previousState needs to be converted to a String by calling the toString method in order to concatenate them together.

In the second case neither triggeringItem.state nor previousState are Strings. Therefore it doesn’t know what the + means. And it’s not smart enough to see that logInfo requires a String as the second argument so it must call toString on both variables before executing the concatenation operation. If you manually add .toString to either operand it will work.

In the third case, again previousState is not a String and the language is not smart enough to see that the second argument to logInfo needs to be a String and therefore to call toString on previousState.

But, in the future @Nicola_Cisternino, please explain how it doesn’t work when something doesn’t work. There is a near infinity of ways that something can go wrong and the helpers on the forum tend to get annoyed when you make us waste time playing 20 questions just to learn what the problem is.

4 Likes

Great explanation, Rich… As always! :blush:

You’re right, @rlkoshak … sorry :roll_eyes:
I’ve just improved my question :slightly_smiling_face:

Thank you, @rlkoshak and @noppes123