Non-final variable in lambda expression for timers

  • Platform information:
    • Hardware: i5-8279U (X86)/ 16GB DDR4/ 512GB NVME SSD
    • OS: Windows 10, version 20H2, build 19042.1348
    • Java Runtime Environment: openjdk version 11.0.12, runtime Zulu11.50+19-CA
    • openHAB version: openHAB 3.2.0.M2

I’ve been trying for a couple of days to create a functioning looping timer for my install based on the examples given here: Design pattern looping timers

I have read several other forum posts that relate to looping timers as well as the rules documentation and I can only assume I am doing something fundamentally wrong. My goal is to check on ‘BEStatusSwitch’ every hour after it been turned off and if it is still off would then send a notification alerting me to its continued downtime.

The problem is that whenever I run the program as it is stated below I get the following error:
‘Cannot refer to the non-final variable inside a lambda expression;’

These errors always blame ‘testy = null’ and ‘testy.reschedule(now.plusSeconds(30))’ inside of the if and else statements respectfully. And removing these statements allows the program to run except for the fact that the program now has no way to reschedule the timer.

If anyone has any idea what I’m doing wrong or could point me in the right direction towards some documentation I haven’t found I would be extremely grateful.

everything is written in ruledsl through either the create a rule inside of main ui or by creating a script in the scripts section in main ui if that helps

var Timer testy = null

  
    testy = createTimer(now.plusSeconds(30), [ |
        if(BEStatusSwitch.state == ON){ 
            sendNotification("myusername", "If has run")
            testy = null
            }
        else {
            sendNotification("myusername", "Else has run")
            testy.reschedule(now.plusSeconds(30))
        }
  ])

The examples you are using are written in ‘files’ style DSL, you’ll notice the when-then-end structure.
The
var Timer testy = null
line is notably outside that structure, forming what’s commonly called a ‘global’ variable. Defined outside of any rule, it exists in a context outside of any rule.

When you define DSL rules using the GUI there is no “outside of the rule” to place a similar variable definition. There are no ‘globals’ for GUI DSL. There is no workaround.

You can use files based DSL or switch to a different rules language like javascript, where ‘global’ type functionality is available.

1 Like

Thank you so much. It never occurred to me that rules created in a .rule file would have different functionality than those created in the GUI. I have no problems with creating the rules textually rather than in the GUI so that makes for an easy fix.

It worked immediately once I put the rule into a .rules file

Is there any documentation that highlights the differences between ‘files’ DSL and ‘gui’ DSL that you know of? or would it be better to just stick with ‘files’ based DSL?

Kinda sorta … the rules proper have the same functionality - but what you don’t have in GUI is access to the context outside of the rule.

In a rules file, the so-called ‘global’ is only shared amongst the rules in that one file, and is inaccessible to rules in other files. The GUI is like putting each rule in its own file.

2 Likes

I hadn’t really thought about the layout too much before now but it makes complete sense.

starting a rule inside of a file basically creates it’s own function that ends with the ‘end’ line. So any variables that are declared in-between ‘rule’ and ‘end’ are self contained. By declaring my variable outside of that it has essentially become independent of the rule but could still be called.

This would allow me to create multiple rules in the same file that shares a variable, but I’m guessing that wouldn’t be recommended since multiple rules within the same file may try to access the variable at the same time and create issues?
On a related note is it just bad practice in general to have multiple rules in one file?

It generally works out fine, so far as the system goes. How the logic of your rules handles it is a matter for your design consideration.

If you look at the timer example that you started with, the purpose of the ‘global’ here is to allow the reference to a newly created timer to “survive” after the rule has exited. In this case, just so that the timer can reschedule itself (it has no other way to reference itself, there’s no “this” in DSL).

Not at all, it is the standard practice. Many folks end up with a handful of files for organisational reasons - one file with all the lights rules, one with the heating, etc.

I really appreciate the information. This has really helped me with some things I had been thinking about with the system “click” for me so to speak. You sir are a scholar and a gentleman.