I have an issue with comparing two string variables. When I execute the code below the logfile states:
RULE[this is a test] dark_start = SUNSET
RULE[this is a test] processed_sun_phase = DAYLIGHT
Script execution of rule with UID ‘datetime-4’ failed: Unknown variable or command ‘==’; line 154, column 8, length 33 in datetime
Does anybody know what is wrong here?
Thanks!
// ===================================================
rule “this is a test”
// ===================================================
when
Item Debug_Define_day_or_night changed to ON
then
val sunphases = newArrayList(
“DAYLIGHT”,
“SUN_SET”
)
val string dark_start = Dark_Sun_Phase.state.toString
logInfo(“datetime.rules”, “RULE[this is a test] dark_start = {}”, dark_start)
var int i = 0;
var string processed_sun_phase = “”
while(i<3) {
processed_sun_phase = sunphases.get(i).toString
if (processed_sun_phase == dark_start) logInfo(“datetime.rules”,“RULE[this is a test] equal”)
i=i+1
}
end
The problem is that your String is not capitalized:
rule a
when
System reached start level 100
then
val string a = "77t"
if (a == "77") logError("A", "B")
end
logs
[INFO ] [el.core.internal.ModelRepositoryImpl] - Loading DSL model 'a.rules'
[ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'a-1' failed: Unknown variable or command '=='; line 6, column 7, length 9 in a
whereas capitalized String works:
rule a
when
System reached start level 100
then
val String a = "77t"
if (a == "77") logError("A", "B") else logError("A", "C")
end
logs:
[INFO ] [el.core.internal.ModelRepositoryImpl] - Loading DSL model 'a.rules'
[INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in DSL model 'a.rules', using it anyway:
Constant condition is always false.
[ERROR] [org.openhab.core.model.script.A ] - C
I suggest to remove the type after val and var, it is the implicitly correct, unless it is ambiguous:
val sunphases = #['DAYLIGHT”, “SUN_SET”]
val dark_start = Dark_Sun_Phase.state.toString
var processed_sun_phase = “”
above sunphases is ArrayList, to make it of type String[] use:
Indeed the capital String solves the issue. Thanks you both!
Not sure what happens in the background with a string variable that is defined with lower case and why the error message is as given. Would it be possible to put a syntax check on defining string variables with lowercase?
Possible perhaps, but not practical/smart. We can’t “ban” the word string, it’s e.g. a valid variable name. In Java/Xtext, types always start with a capital letter if they aren’t primitives (int, boolean, long, double etc.).
The most reasonable thing would be to remove from the examples in the openHAB Documentation the explicit types provided to variables and constants (val and var), when these types are not necessary at runtime, when the types make no difference at runtime. This way users will not do spelling mistakes, when they try to spell the return type. Currently the documentation has examples with val int dimAsInt = dimVal.intValue, so a user logically concludes that it is similar to write val string text = item.state.toString.
As to int vs Integer in variable types, I do not think it makes any difference here. It would make difference, if Xbase was used to generate .java files, but in openHAB Xbase is used to interpret the code. In the past I tried to create variables of types int and Integer, then called on them .class.toString and in both case the class was the same - so even Java primitives, when interpreted by Xbase, are the same as the corresponding object.
In question of int vs. Integer, there is a difference.
Please try it by yourself:
// test 1
var int myInt = 0
myInt ++
// test 2
var Integer myInt = 0
myInt ++
// test 3
var int myInt = 0
myInt +=1
// test 4
var Integer myInt = 0
myInt +=1
rule a
when
System reached start level 100
then
var int a = 0
var int b = 0
var Integer c = 0
var Integer d = 0
a++
b+=1
c++
d+=1
logError("A", a.toString)
logError("B", b.toString)
logError("C", c.toString)
logError("D", d.toString)
end
I made a change to the logXxx() methods in 5.2.0, so you no longer needs to send a string as the 2nd argument. toString() will automatically be invoked if the object received isn’t a string.
Traditionally in other languages we’d get an error message saying that string is invalid or something. That would’ve avoid this entire thread since the user would immediately see what the problem is.
Invalid explicit variable type does not produce proper error in DSL Rule, but correct error message in DSL Scripts, because errors and warnings originating from Xbase are handled differently for DSL Scripts and DSL Rules by ModelRepositoryImpl.validateModel:
switch (modelType) {
case "rules":
if (d instanceof AbstractValidationDiagnostic vd
&& d.getSeverity() == org.eclipse.emf.common.util.Diagnostic.ERROR
&& ("uid".equals(vd.getIssueCode()) || "time".equals(vd.getIssueCode())))
errors.add(d.getMessage());
else
warnings.add(d.getMessage());
break;
case "script":
warnings.add(d.getMessage());
break;
default:
if (d.getSeverity() == org.eclipse.emf.common.util.Diagnostic.ERROR)
errors.add(d.getMessage());
else
warnings.add(d.getMessage());
}
So errors and warnings from DSL Scripts are converted to warnings, whereas some errors from DSL Rules are kept as errors and others are converted to warnings and later this apparently makes a difference.
Using openHAB 5.3.0 build 5492 this DSL Script
var string s = "abcdf"
if (s == "abc") logError("A", "B") else logError("C", "D")
prints at runtime:
[INFO ] [el.core.internal.ModelRepositoryImpl] - Loading DSL model 'b.script'
[ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'b.script' failed: var ___ string s = "abcdf"
if (s == "abc") logError("A", "B") else logError("C", "D")
string cannot be resolved to a type.; line 1, column 4, length 6
whereas this DSL Rule:
rule a
when
System reached start level 100
then
var string s = "abcdf"
if (s == "abc") logError("A", "B") else logError("C", "D")
end
prints
[INFO ] [el.core.internal.ModelRepositoryImpl] - Loading DSL model 'a.rules'
[ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'a-1' failed: Unknown variable or command '=='; line 6, column 7, length 10 in a
To recap what I remember here, it was like this: Originally, DSL errors were converted to warnings, which caused confusion, and it was changed at some stage. This broke a lot of rules, because the rules are parsed before all valid objects/contexts exist during startup. So, the conversion to warning was reintroduced, because it’s there to allow rules that aren’t valid at one point, but that become valid later, to exist without failing.
When we made the UID validation, we needed those exact errors to still be actual errors, which is why I made this “hack” to allow designating some errors as “true errors”.
Reverting all errors to errors, will reintroduce the problem with rules being parsed before everything is ready.
The real solution to this is to control the startup order in a way that makes sure that those objects/contexts exist in time for the evaluation. Only then can the “error → warning hack” be removed. But, until somebody figures out how to make sure of this, the hack must remain.
Are you saying that the explanation about things not being ready in time is wrong? I didn’t study that myself, I only read it, and it seemed plausible.
If the errors that caused the reversals are indeed “real errors”, I think it’s time to prepare to change it back. Perhaps actually logging them as errors for a while, combined with “this will cause the rule to fail in a future release” might be the correct way to go.