Whenever I do some calculations in a Script or rule with variables that were declared as double the result seems to be of BigDecimal type. This is annoying when I want to further use the result as an argument to a java.lang.Math-function which expects arguments of type double.
Also, I would really like to keep computational effort low and therefore do all calculations in double. I think, BigDecimal has a much higher computational demand.
Is there any way to make the rule engine respect my declared variable types?
BTW: are rules and scripts pre-compiled when the log message says “Refreshing model” or interpreted at every trigger?
…and, thanks for the great work to all the developer!
I’m going to make some wild assumptions based on a little reading and some interpretation. I could be completely wrong.
Given that Rules and Scripts use a Domain Specific Language built on the Xtend language I’m going to assume that anything that is true for Xtend will be true for openHAB. Since “Xtend is a statically-typed programming language which translates to comprehensible Java source code” and Java pre-compiles to byte code I’m going to say that the rules do indeed get pre-compiled. Indeed this can explain some of the limitations of the language such as being able to get a reference to an Object if all you have is the name as a String.
Whether they get compiled at “Refreshing model” or just before their first use is just a guess but I’m thinking they are initially converted to Java and then compiled to byte code when the rule’s files are loaded. My reasoning is that you will get syntax errors at load time and I wouldn’t expect syntax errors until it tries to compile.
See the Number Literals section of the Xtend Expressions documentation. I know you can force the primitives to be of a given type using the suffix (e.g. ‘D’ for double), and according to the operators documentation further down on the page the following:
val double a = 1.1D
val double b = 1.2D
val c = a + b
Should be equivalent to:
val double a = 1.1D
val double b = 1.2D
val c = a.operator_plus(b)
But I can’t find an operator_plus method on Number, BigDecimal, or Double so I have no idea where that gets defined. It is entirely possible that it always returns a BigDecimal though.
You can convert it back to double by calling doubleValue on the result.
Out of curiosity, what are you doing with openHAB where the computational difference between using BigDecimal and double makes a difference? This raises all sorts of red flags to me. Either you are worried about performance needlessly (very few home automations deployments are sensitive to difference of dozens of milliseconds) or openHAB is not the right tool for your problem (maybe move the calculations off to a separate script written in a language tuned for this kind of performance that openHAB calls through the Exec binding).
That being said, if you are really concerned about computational effort, you should be converting everything to longs for your calculations and only converting back to double when you are done. (e.g multiply by 1000 to preserve three decimal places, do your math, divide by 1000 to get back to your double). Integer math is usually more efficient (and accurate).
Thanks for the fast response.
I also read some of the Xtend documentation and understood that the operator methods are all implemented for basic types. And I would assume that, when an operator method is implemented for a certain type, then the result should be of the same type.
What is really strange is that at least openHAB Designer doesn’t seem to honor the declared type of a variable. When you hover over a variable name it always says that the variable is of type XVariableDeclaration no matter how it was declared. So that makes me wonder. Maybe one of the developer could shed some light on this.
Regarding your question: I am just calculating some absolute humidity values for my basement venting algorithm. At the moment the difference between BigDecimal and Double sure shouldn’t make much of a difference. Maybe I’m just a bit to efficiency-focused from all the micro-controller programming (efficiency junky)
But then again, I’m running openHAB on a RPi B and would like to keep it that way, even with many more items and rules to come.
Even on a Raspberry Pi I don’t think you will notice much if any practical difference between using BigDecimal and Double until you had hundreds or thousands of such calculations a second for a sustained period of time. Since almost everything in openHAB operates on periods of seconds or minutes I just can’t imagine how this will ever make a difference. Besides, there is soooo much else going on in openHAB that has orders of magnitude more impact on performance than calculations like these (e.g. the event bus) that even if you got it as efficient as possible you would see little to no actual change in overall performance.
This sort of thing is something I wouldn’t worry about until it actually became a problem. And if it did become a problem I’d probably move it out of openHAB and into an optimized C program that openHAB calls. OH is simply not designed to operate that efficiently.
As much as I sing the praises of Designer and recommend it to everyone, it is not perfect. Because Xtend isn’t a strongly typed language I don’t think Designer has the ability to always determine the type of a variable so it doesn’t try and just shows the lowest common denominator (XVariableDeclaration). The fact that the hover feature works at all probably has more to do with the fact that it was built on Eclipse than that the feature is useful. This sort of tooling is one of the advantages of using a strongly typed language I suppose.