At what point does stacking expression binding functions become too much?

Expression functions are nice because they are snappy and will execute instantly on a variety of different inputs. I’ve gotten decent enough at the expression language to accomplish basic animations for labels and such by stacking multiple nested ‘if’ statements, while also parsing the tagPath to read other tags in the UDT. I used to just do this using a script transform, but there really is no need due to the ability to stack all these functions into one expression binding.

Here’s an example. I’m thinking about rolling this out on a lot of backgroundColor bindings, but I wanted to see if this seemed a little too heavy to put in on hundreds of tags:

if((tag(concat({this.custom.key},"/Alarms.HasActive")) && isGood(tag(concat({this.custom.key},"/Alarms.HasActive")))),"#FF0000", 
if(isGood({this.custom.key}) = False,"#FF00FF",
if(tag(concat(replace({this.custom.key}, right({this.custom.key}, len({this.custom.key}) - lastIndexOf({this.custom.key}, "/")), ""), "/AUTOSOL TAGS/COMMUNICATION ALARM")), "#FF00FF", ""
)
)
)

I don’t think we have any hard rules about expression complexity and performance.

I’d be more concerned with at what point does your expression become unmaintainable, to others and to your future self.

1 Like

About the maintainable part, is there any syntax to pop a comment in an expression?

if(condition1,
1, --Comment about why we return a 1
null --Explanation of fallback value
)

I would say stack away. Except for anything asynchronous, like tag().

Of course, if you’ve used tag() anywhere other than an expression tag, you’ve already screwed up. ):

Comments work, this is a valid expression:

if(1,
// true 
"foo", // here too
// false
"bar" // and here
)
1 Like

What do you mean by staying away from tag() if its outside of an ‘expressoin tag’. From my understanding, the expression language is available in a handful of locations:

  • Expression tags

  • Bindings - Expression binding, tag expression binding,and expression structure.

The tag expression binding seems to be fairly limited. It don’t know if you can actually use expression functions, it seems to be really used just to dynamically create tag paths to be read.

Whereas, just an expression binding seems to allow more functionality. Are you saying that using tag() in this scope is a bad idea?

Can you give me any insight to performance hits associated with expressions vs just having something like this run on a timed expression now() transform that runs a python script?

From my little understanding about software development, it seems like to be the expression language is a pretty low-level type of language that is quickly compiled into assembly code natively. Whereas a python script requires another gateway program to read the script, and then compile it into assembly (since it is a interpreted langauge).

So, from my perspective, it seems like these expression functions basically just access some low level language (like C, or maybe just Java?), and the developers have build optimized functions that can execute those functions rather rapidly, and can compiled and executed very quickly? Like a lot quicker than running a python script?

I’m also curious about the performance hit on using a bunch, like thousands if not tens of thousdands, of expression tags and expression bindings. From my understanding, they can be ‘dangerous’ because they essentially fire like all the time. I’ve found this to be most dangerous if an expression tag is tied to a python script that can eat up a lot of gateway resources. I like to use expression language to perform basic tasks and operations like my example above.

I know its impossible for developers to give hard guidelines on something like, ‘well if you have more than x number of expressions, and your server has x resources, then stop’. I guess I’m maybe just interested in best practices. Ignition has so many different ways to accomplish the same task, and often times I find that there is a lot of grey area on what is bad vs good. For the scope of this specific discussion, I have a script that turns the background color of a label based on if its an alarm, or if another value inside a nested UDT of the parent instance has a specific value. I really liked using expression language to perform this task. Is there a better way?

Sorry for being so verbose. Thanks for any insight.

Couldn’t you use expression structures, and some transforms like maps and such, to accomplish your goal with more readability ?

Also, I’d say the expression language is pretty high level, which doesn’t mean slow in any way, it just means the details of implementation have been abstracted away. Even Java I wouldn’t consider low level.

The expression language is just a relatively fast parser that executes a stack of Java functions. Once compiled, Jython or an expression are going to run about the same speed, or at least comparable. The main penalty you pay for Jython is the overhead of starting an interpreter; Python code is a whole lot more complicated to parse, because there’s control flow, variables, etc.

That said, this reeks of premature optimization. I would argue, design for the system you can maintain, six months/six years down the road - worry about performance if it becomes a problem. Using expressions is generally easier to reason about than scripts, purely on the basis of it being (almost) impossible to execute side effects…but the lack of variables can also seriously hurt a complicated expression’s readability.

1 Like

OK. I can certainly agree about the importance of readability and maintenance down the road. So, from your perspective, what could I change about this code to help meet those needs? Expression structure? More comments?

We’ve ran into performance issues in the past, and when the gateway is unstable, it’s worse than having some code that is just hard to debug. Ideally, we need the best of both worlds. I think as an integrator, both optimization and ease of use need to be considered equally. Especially with a system as large as the one I am tasked with. I often find that we find better and better ways to do things, as I become much more proficient, and as the perspective module matures.

Thanks for any other constructive feedback, I really do appreciate all the advice given so far.

Trent

Some discussions (and rants) are easily found with my ID and "tag()" in a search. You can start with this topic, though:

This would shock me. Even compiled, Jython has a lot more "going through one's [expletive] to get to one's elbow" gyrations. Including wrapping and unwrapping java objects / jython objects. Expressions blow jython out of the water. IIRC, @nminchin tested this for us, to that effect.

1 Like