[SOLVED] "triggeringItem" null for system started

(Rossko57) #22

Yes. Whether you have two separate rules, or one rule with both cron and system triggers, makes no odds. Two separate rules trigger, or one rule triggers twice (event driven, not state driven). Neither solves a desire for run-once, so you would need some extra logic unrelated to rule triggers to sort that out.

0 Likes

(Joachim Boeddeker) #23

Yes.

First of all, if a rule is triggered by system started or cron, there is no triggering item. So you can’t use it anyway. Putting everything in a single rule and deciding inside the rule if it’s cron, item or system started triggered adds complexity. openHAB is able to decide it on its own and fires the apropriate rule.

Let a rule perform exactly one task, everything else makes everything more complicated.

Again, let openHAB fire the appropriate rule. If you need the same logic twice, put that into a script and call it from both rules.

You want the following (be aware, non working pseudocode):

rule "xyz"
when system started or cron or item
then
    if trigger==system started do x
    if trigger==cron do y
    if trigger==item do z
end

And i say, do it that way:

rule "x"
when system started
then 
   do x
end

rule "y"
when cron
then 
   do y
end

rule "z"
when item
then 
   do z
end
0 Likes

(Rich Koshak) #24
if (triggeringItem !== null && triggeringItem.name == "plug_reachable")

If this line is using left-associative short cirtuit evaluation then it would:

  1. evaluate the triggeringItem !== null
  2. if 1 evaluated to false, since one operand is false it knows the && can only return false
  3. nothing after the && gets executed and thus the call to triggeringItem.name never happens.

But the exception above is showing that it IS evaluating the triggeringItem.name and throwing a NPE which means Rules DSL is either not implementing short circuit evaluation with && and ||, or not implementing left-associative evaluations with && and ||. In either case, Rules DSL is not acting like most other programming languages in this respect.

I’m not saying the way that Rules DSL does it is wrong, per se, but it is unusual and unexpected.

I like the idea and there are ways to figure this out in the Next Gen Rules Engine I think (system started wasn’t working last time I tried it so I can’t say definitively). I don’t know how supportive ESH will be in adding a feature like this to the Rules DSL since they are making a lot of efforts right now to make the NGRE no longer experimental. But it is certainly worth an issue on the ESH project.

It should support more than just System started and Time but also include Thing Channel triggers.

Sometimes you have to be wary of the XYProblem. This is when you ask for help with trying to solve a problem in the way you have already decided the problem needs to be solved. Letting the forum know what your ultimate goal is opens to aperture and lets us offer completely different solutions to the problem which may work better.

You’ve definitely uncovered a behavior in the Rules DSL that is unexpected and undocumented though.

0 Likes

(Michael Ingraham) #25

Guilty as charged :wink:

I understand that the NGRE is where resources are being devoted and rightly so.

Mike

P.S. I haven’t yet taken the plunge to try that out. I did when I first started playing with OH in the spring… and it was too shaky or lacked key capabilities. Obviously lots of water under the bridge and lots more effort devoted to it. I’m not a bleeding edge kind of person though… so I’ll probably keep using DSL. Also, I do find that GUI stuff is pretty laggy running on my RPi3B. I’m leery of using a GUI interface for rules if every click is met with pretty substantial lag.

0 Likes

(Joachim Boeddeker) #26

I used many programming languages and they all would behave like that, at least from memory. Java as well. Have a look here https://introcs.cs.princeton.edu/java/11precedence/. The equality is analyzed before &&, so the lazy execution is too late. Before the system may decide to not analyze the second part of the &&, the exception is already thrown.

0 Likes

(Michael Ingraham) #27

Ah, but scenarios are not always quite that "segmented. If this was the case, I would agree with you. My scenario is more like this:

rule "xyz"
when system started or cron or item
then
    if trigger==system started do a, b, c
    if trigger==cron do a, b
    if trigger==item do b, c
end

In reality it would be if/else, but for sake of argument…

Yes, I could break that up into separate rules and replicate the a, b, & c task logic as needed. But then I have duplicate code which if change is required, requires multiple places to be updated… or more likely, multiple places to forget to update.

Mike

0 Likes

(Michael Ingraham) #28

Bad example on my part. Yes, the two events could happen concurrently and the logic ought to handle them if the desired outcome is to treat them as one. But, if the cron happens and it’s not during a restart, then perhaps the rule doesn’t do some of the tasks, etc.

0 Likes

(Joachim Boeddeker) #29

put that code in the scripts a.script, b.script and c.script and call them from the rules.

rule "x"
when system started
then 
   callScript("a")
   callScript("b")
   callScript("c")
end

rule "y"
when cron
then 
   callScript("a")
   callScript("b")
end
rule "z"
when item
then 
   callScript("b")
   callScript("c")
end
0 Likes

(Rossko57) #30

Info only; XTEND docs do describe “Short-Circuit Boolean Operators” here
https://www.eclipse.org/xtend/documentation/203_xtend_expressions.html
but that does not mean it carries into rules DSL

0 Likes

(Joachim Boeddeker) #31

Exactly, Boolean. But before the booleans exists, the exception is thrown.

0 Likes

(Michael Ingraham) #32

But many times a, b, & c aren’t completely “independent”. There are situations when a result from a causes b or c to behave in a different fashion. You can’t pass parameters to a script or receive a return value. I guess you’d have to do everything through Items - EVERYTHING becomes a global variable. Uggh.

Mike

0 Likes

(Joachim Boeddeker) #33

If your code fragments are dependent on each other, you can’t use them as you described.

What about providing a real problem and let’s try to solve it, instead of this academical discussion. I can’t think of similar logic to be run on system started, cron or item based, which is also not independent from each other.

0 Likes

(Rich Koshak) #34

Yes, but the left side is evaluated before the right side. So the order would be: !==, == (only if !== was true), &&. The whole point of short circuit evaluation is to avoid any side effects from the second operand from occurring if the first operand evaluates to false. In this particular case, it should prevent the NPE on the call to triggeringItem.name because that is never executed. That’s what short circuit means.

Now we can argue whether it is a good idea to have operands in an if statement that cause a side effect in the first place (IMHO it is a colossally bad idea).

And the very article you linked to backs me up:

Short circuiting . When using the conditional and and or operators (&& and ||), Java does not evaluate the second operand unless it is necessary to resolve the result. This allows statements like if (s != null && s.length() < 10) to work reliably.

The emphasis is mine and the example is exactly the same as the case here.

In Java, if (triggeringItem !== null && triggeringItem.name == "plug_reachable") would be fine because the right hand operand would never be evaluated and the NPE never thrown because of the short circuit.

Do a, b, and c need to be done exactly in sequence? Instead of splitting the Rule up by trigger, break them up by a, b, c.

  • Rule a triggered be system started or cron
  • Rule b triggered by system started, cron, or item
  • Rule c triggered by system started or item

Somehow I missed that when I looked. That section does say

Still you can overload these operators for your types or even override it for booleans, in which case both operands are always evaluated and the defined method is invoked, i.e. no short-circuit execution is happening.

Perhaps they overloaded the operators in Rules DSL without realizing it would cause this side effect. That seems a reasonable explanation.

No because the triggeringItem.name is never executed in a proper short circuit evaluation.

0 Likes

(Rossko57) #35

if (triggeringItem !== null && triggeringItem.name == "plug_reachable")

Thinks; the problem here is I suspect not that the right hand eval fails, but the left hand one does.
If there is no triggeringItem (because we triggered from system, say) then it is not a case of triggeringItem=null, there simply is no triggeringItem. The failure is undeclared variable.

I suppose there is some kind of ‘variable exists’ test that could be substituted

0 Likes

(Rich Koshak) #36

As far as I’m aware there is no other way to represent that except as null. So I would expect to either get a NoSuchSymbolException or some such were that the case or the engine would treat a reference to a non-existent symbol as null in which case null !== null would evaluate to false and we wouldn’t see the exception that there is no name method on null.

I don’t have time to test this myself right now (I’m about to sign off for the day), but it would be easy enough to test. Create a cron triggered Rule and log triggeringItem. If it logs “null” then we know that it is being treated as null. If it throws an error then we have evidence that your hunch is correct.

I can say with certain though that in the NGRE, the equivalent of triggeringItem will be undefined, at least in JavaScript action scripts.

0 Likes

(Rossko57) #37
rule "Clock tick"
when 
	Time cron "0 0/1 * * * ?"   // each minute
then
	if(triggeringItem===null) {
		logInfo("testit","Surprise")
	}
end

Error during the execution of rule 'Clock tick': The name 'triggeringItem' cannot be resolved to an item or type; line 12, column 5, length 14

For completeness,
if(triggeringItem===null && triggeringItem.name=="blah")
throws the identical error (nothing about name)

triggeringItem is working as designed, as described here

I think there has been some mixup about what code provoked which failure.

1 Like

(Michael Ingraham) #38

Your code has no Item for which there would be a triggeringItem.

My error was not unresolved triggeringItem. Mine was that triggeringItem was null when I tried to retrieve the Item’s name.

[ERROR] [ntime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'Set myVisibility': cannot invoke method public abstract java.lang.String org.eclipse.smarthome.core.items.Item.getName() on null
0 Likes

(Rossko57) #39

Okeydoke, further experiments (OH2.4 M5)

rule "Clock tick"
when
	Item testSwitch changed or
	Time cron "0 0/1 * * * ?"   // each minute
then
	if (triggeringItem===null) {
		logInfo("testit","Surprise")
	}
end

When cron triggered, I did get a surprise !!
triggeringItem is brought into being by the mere existence of an Item in the trigger case. NOT just by an Item being the actual trigger cause (but of course then it is a null variable).

Further experiment to more accurately reproduce the && case

rule "Clock tick"
when
	Item testSwitch changed or
	Time cron "0 0/1 * * * ?"   // each minute
then
	if (triggeringItem!==null && triggeringItem.name=="blah") {
		logInfo("testit","named Item")
	} else {
		logInfo("testit","cron tick")
	}
end

This works as expected - upon cron trigger, we get cron message (because triggeringItem is null)

That is to say, the right hand if-condition is not attempted, and short cut evaluation is working as expected for me.

Attempting in the other order
if (triggeringItem.name=="blah" && triggeringItem!==null)
gives the expected getName() error

1 Like

[SOLVED] The rule triggering cause
(Michael Ingraham) #40

I’m running openHAB SNAPSHOT 2.4.0~20181105174706-1 (Build #1413)

0 Likes

(Rossko57) #41

I doubt short-cut evaluation has changed since OH1, to be honest

0 Likes