Jump to content

LabVIEW constant values change


Recommended Posts

I see advantages of "constructor" method solution (flexibility, DD/ inheritance, ...). But this produces huge init VI BD (see example for only5 nested objects and imagine the same for 100 objects). I'd like to have something more readable/maintainable. How do you manage initialization/"construction" of hundreds of nested objects?

Snap_001.png

Link to comment
9 minutes ago, Petr said:

I see advantages of "constructor" method solution (flexibility, DD/ inheritance, ...). But this produces huge init VI BD (see example for only5 nested objects and imagine the same for 100 objects). I'd like to have something more readable/maintainable. How do you manage initialization/"construction" of hundreds of nested objects?

Short answer: Make it table driven.

Long answer: As you scale up like that, you're entering the realm where you aren't going to code those values directly into G. You may be looking at

  • an array of values in G that you loop over to create objects
  • a binary file where you read back the objects you serialized earlier
  • or something as complex as a SQL database with relationships between multiple tables and you process the entire database to create your object layout. 

These are just suggestions. There are many other options. The point is, you need to make your construction more data-driven instead of directly coded. This is true of all programming languages I've seen, not just G. The notation of objects is such that they come into being as data drives their existence. It's relatively easy to create an object with a given value, and if you're building up objects as they come into existence within a system, everything works fine. But to create an entire system of objects in one burst, you need a data structure that can describe an entire system. That's why things such as object databases exist. 

Link to comment
On 12/18/2018 at 5:10 AM, Petr said:

But this produces huge init VI BD (see example for only5 nested objects and imagine the same for 100 objects)

It's worse than what you show. I see a lot of typedefs there. One issue with your approach is that there is no guarantee your values will remain when you update your typedefs. I have been using LabVIEW long enough to know that you should never trust typedefs on the block digram to keep the values when they get updated. I would change your code right now because it will fail in the future.

Link to comment
19 minutes ago, Michael Aivaliotis said:

It's worse than what you show. I see a lot of typedefs there. One issue with your approach is that there is no guarantee your values will remain when you update your typedefs. I have been using LabVIEW long enough to know that you should never trust typedefs on the block digram to keep the values when they get updated. I would change your code right now because it will fail in the future.

Is that true in the recent versions? The typedefs got revision protection in LV 2015, I think. If the mutation is going to throw away data, it does the same sort of "relink" behavior as when changing conpanes of subVI so you preserve the data. 

Link to comment
2 minutes ago, Aristos Queue said:

Is that true in the recent versions? The typedefs got revision protection in LV 2015, I think. If the mutation is going to throw away data, it does the same sort of "relink" behavior as when changing conpanes of subVI so you preserve the data. 

I'm confident you have data to support your argument. However, I've been burned so many times that I cannot keep track of if it was fixed or what version it was fixed or even if it was fixed but is buggy and it works only under certain conditions. I have lost money because of this and don't risk it anymore. Sorry. But the fact that it was an issue for so many years and only addressed in 2015, gives me pause. Again, not doubting your statement, but I don't trust it.

Link to comment
17 hours ago, Michael Aivaliotis said:

I'm confident you have data to support your argument. However, I've been burned so many times that I cannot keep track of if it was fixed or what version it was fixed or even if it was fixed but is buggy and it works only under certain conditions. I have lost money because of this and don't risk it anymore. Sorry. But the fact that it was an issue for so many years and only addressed in 2015, gives me pause. Again, not doubting your statement, but I don't trust it.

It's definitely fixed in LabVIEW 2016, although it can be a pain. LabVIEW will break all VIs where a cluster or enum typedef is present whose elements contain values that it can not mutate unambigously. And you get a dialog that lists all those locations and it shows you an old and new view of the data (with a best guess for the new value) where you have to edit/select the new data value and then confirm to use that from now. This applies to enum values that somehow changed their name (or were removed) as well as to cluster elements with different name or a reordering that makes it impossible to reassign the old values unambigously.  Simply removing an element in a cluster or enum does however leave the other elements data intact, so it does a reassignment based on label/name rather than just oridinal order of the data.

It's a huge improvement, although it can feel a bit painful at times as an entire hierarchy can seem to break completely because of a minor edit in an enum label.

Edited by Rolf Kalbermatter
  • Sad 1
Link to comment
5 hours ago, Rolf Kalbermatter said:

It's definitely fixed in LabVIEW 2016, although it can be a pain. LabVIEW will break all VIs where a cluster or enum typedef is present whose elements contain values that it can not mutate unambigously. And you get a dialog that lists all those locations

Yes, I remember when this feature came out. I was very happy about it. Then I foolishly trusted it. Then I discovered a bug in this feature by accident. The auto-mutation failed. So now I was burned again by a feature that I was suppose to trust to solve the original problem. You see why I'm shell-shocked.

  • Sad 1
Link to comment
  • 3 years later...
On 12/21/2018 at 3:32 PM, Michael Aivaliotis said:

Yes, I remember when this feature came out. I was very happy about it. Then I foolishly trusted it. Then I discovered a bug in this feature by accident. The auto-mutation failed. So now I was burned again by a feature that I was suppose to trust to solve the original problem. You see why I'm shell-shocked.

Yeah, I've been burned by that as well, but I do find that the feature can be extremely useful if you use if carefully.

The absolute worst aspect of this issue (pre-LV2016) was that sometimes updating a typedef'd enum would revert a block-diagram constant to its default (or was it a random?) value silently (and of course without breaking the VI, just its functionality). That would wreak havoc with any state machine, for instance, that used an enum to switch state cases. Thank goodness that's behind us.

If I want to update a cluster or enum typedef post-LV2016 I very carefully observe the following rules:

  1. Adding elements to clusters or items to enums is generally safe and can be done with abandon. (Especially if you don't enable defaults in enum-switched case structures.)
  2. Changing the name of a cluster element seems safe, as does reordering elements.
  3. Changing the item string of existing enum items also seems safe.
  4. When deleting enum items, delete only one item, save and close the typedef, and then go clean up the ramifications in the codeset. Repeat the full process until you've deleted all the items you want. The algorithm doesn't seem to get confused with such a simple, non-compound change. Never delete and add enum items in the same operation!
  5. Deleting cluster elements might also require the approach for enums, but I never ever use the values in cluster constants, even strict typedef'd ones. I always initialize in-situ or make an init VI to handle that. So I never run into problems deleting and adding elements to a cluster in one operation.

Heh, I came here to ask a different question about Class constants and the mutation history, but couldn't resist responding to Michael first.

Link to comment

I've been burned by another issue involving class private data saved anywhere other than the class private data control definition itself.

Specifically, I've had the App Builder fail to compile or build .exe's that come up broken in the runtime when I have class private data saved in a block-diagram constant or an FPC--and when that data is in a previous structural form reliant on the class mutation history. I never intend to invoke the class mutation history, in fact I'm not sure I knew it existed until I ran into the problem. But it's easy to do accidentally and afaik there's no way to tell without building tooling outside the IDE, so this falls into the silent-but-deadly category of not having visibility into automated mutations.

The easiest way to fix this issue is simply to delete all mutation history for all classes I'm using (since I have no backwards-compatibility needs). But that's yet another thing that I have to remember to do or add to build automation, and it's philosophically wrong. (It works, so I do it...) But that got me thinking if there might be a way to avoid the issue in the first place and I haven't figured out a way to do it, and in the process I realized I just don't understand how saved class default values are handled.

Even if I'm going to explicitly initialize all class private data, the class itself has to be instantiated using a BD constant or a FPC, right? Before running into mutation history problems I used to just use a BD constant in some sort of constructor VI. Then I changed it to the following approach:

image.png.318c5de03a507ca8958313db80490526.png

image.png.ca075389f2114b1833b8082df63887d5.png

This is the "Create" VI for a class, sorry about the embedded editorial, that's how I felt when I wrote it. Note that the class control doesn't appear on the conpane, so I'm using it like a constant to instantiate the object.

But I'm not sure that this approach actually does anything. When I plunk the class control on the front panel presumably it gets the current default value of the private data control, but what happens then? Is it ever updated automatically?

Experience leads me to believe that if I never explicitly save a default value for the class control in this VI, any changes I make to the class private data structure will propagate to that control and the class mutation history won't be invoked. But maybe that's not true, I have only anecdotal evidence, so asking here. If it is true then the invoke node above is redundant. But even if the invoke node above isn't redundant, maybe it initializes the private data to the previous private data structure version still dependent on the mutation history.

And if I somehow accidentally explicitly saved the default data on that control, I'm realizing now that the code above probably doesn't help me with the App Builder anyway, since presumably the builder knows nothing about the runtime effects of the invoke node.

Unfortunately, even if I figure out how to handle bypassing the mutation history at object creation, it turns out that the problem with the App Builder can be invoked by any saved default value on a class control anywhere in the code, even if that control is always on the conpane and required to be connected. After I knew about this issue I still managed to trigger it in UI VIs where I was in the habit of setting a bunch of front panel controls and then saving them with "Make Current Values Default" in the edit menu, in the process saving the class control default as well. At that point nothing breaks, it's only several weeks later when I change around something in the class private data definition, and "inexplicably" I can't make .exe's anymore. With any luck I only end up spending a few hours tracking it down, facepalm myself, delete the mutation history, tell the IDE to, yes, go ahead and throw away the incompatible saved default values, and all works again.

So: when are class private data default values saved, and are they ever automatically updated? Is that documented in the documentation and I missed it somehow? Is there a way to get around this issue other than deleting class mutation history?

If deleting class mutation history is indeed the best approach, then perhaps it should be available as an explicit operation in the IDE. In my case it might be even better if there were a global setting to not save class mutation history in the first place.

 

 

Link to comment
5 hours ago, kej said:

Specifically, I've had the App Builder fail to compile or build .exe's that come up broken in the runtime when I have class private data saved in a block-diagram constant or an FPC--and when that data is in a previous structural form reliant on the class mutation history. I never intend to invoke the class mutation history, in fact I'm not sure I knew it existed until I ran into the problem. But it's easy to do accidentally and afaik there's no way to tell without building tooling outside the IDE, so this falls into the silent-but-deadly category of not having visibility into automated mutations.

Class constants and controls have black background when they contain non-default values:

1379106495_Non-defaultconstant.png.9159cc2ead83753c0a691b03d8e4e0f9.png

5 hours ago, kej said:

Even if I'm going to explicitly initialize all class private data, the class itself has to be instantiated using a BD constant or a FPC, right?

Class constants (and controls) always have the default value of their private data control unless you explicitly create a non-standard constant like in the example above.

5 hours ago, kej said:

But I'm not sure that this approach actually does anything. When I plunk the class control on the front panel presumably it gets the current default value of the private data control, but what happens then? Is it ever updated automatically?

It is updated every time the private data control is changed. This is why VIs containing the class are broken until the changes to the private data control are applied.

image.png.3a522d2b82614629fe4bbce93e0c3f13.png

5 hours ago, kej said:

Experience leads me to believe that if I never explicitly save a default value for the class control in this VI, any changes I make to the class private data structure will propagate to that control and the class mutation history won't be invoked.

That is correct.

5 hours ago, kej said:

But maybe that's not true, I have only anecdotal evidence, so asking here. If it is true then the invoke node above is redundant. But even if the invoke node above isn't redundant, maybe it initializes the private data to the previous private data structure version still dependent on the mutation history.

It does not. The default control does not actually contain a copy of the private data control, but a value to indicate that it returns the class default value. Even if you make this value its default value, it is still just a value that indicates that it returns the class default value.

Only when the background turns black, you have to worry.

5 hours ago, kej said:

Unfortunately, even if I figure out how to handle bypassing the mutation history at object creation, it turns out that the problem with the App Builder can be invoked by any saved default value on a class control anywhere in the code, even if that control is always on the conpane and required to be connected.

By any chance, do you write values to class controls?

This can result in undesired situations when combined with 'Make Current Values Default':

540775997_WhatamIdoing.png.758b09c0b262d224ccb792a4b288cb6e.png

2022-11-30_10-07-25.gif.07540c0a721abeb03504f6dcfd20bf65.gif

Edited by LogMAN
  • Thanks 2
Link to comment

My understanding is that the class mutation history is present in case you try and deserialise from string. It is supposed to "auto-magically" work even if a previous version of the data is present.

This is a terrible feature that I wish I could permanently turn off. I have had lots of weird bugs/crashes especially when I rename class private data to the same name as some other field that was previously in it.

This feature also considerably bloats the .lvclass file size on disk.

For those not aware, you can remove the mutation history like this

image.png.8983dbfabdbe0be9d3f2c4ad0d2d450b.png

Link to comment

Wow @LogMAN, that was a thorough reply, thank you! The black background/outline on the object icon is a key thing I was missing.

You asked:

8 hours ago, LogMAN said:

By any chance, do you write values to class controls?

This can result in undesired situations when combined with 'Make Current Values Default':

540775997_WhatamIdoing.png.758b09c0b262d224ccb792a4b288cb6e.png

I never write to class controls, in fact it's never occurred to me to do that! And I don't think I would ever want to do that.

A long time ago I decided never to use property nodes for private data access. I will do a little research to see if I should reconsider that...

Instead, within member VIs I always use bundle/unbundle, outside the class I use getter/setter methods. I'm happy to make custom getter/setters if I need to access some arbitrary set of the private data.

When appropriate, my favorite idiom within the class is to use the Unbundle/Bundle Elements border node of the In Place Element Structure. I write a lot of RT code where I need to preallocate memory and use in-place. For example:

1400855388_IPESexample.png.eacf1005711cfab47f3633b07f0523d0.png

Link to comment
1 hour ago, kej said:

A long time ago I decided never to use property nodes for private data access. I will do a little research to see if I should reconsider that...

Instead, within member VIs I always use bundle/unbundle, outside the class I use getter/setter methods. I'm happy to make custom getter/setters if I need to access some arbitrary set of the private data.

Yes, this makes sense for class members. They should always access the private data cluster directly. Property nodes are only good for callers (and maybe when accessing parent class data).

In the past I also avoided property nodes. Mostly because of stability and performance issues (~2011-2015). Nowadays they appear to be stable and are just easier to read (also, I'm lazy and property nodes don't need icons 😏).

1 hour ago, kej said:

When appropriate, my favorite idiom within the class is to use the Unbundle/Bundle Elements border node of the In Place Element Structure. I write a lot of RT code where I need to preallocate memory and use in-place.

This is probably the best way to do it. Read-only and write-only access, however, should still be done with standalone bundle/unbundle. It makes it easier to understand what is going on, avoids unnecessary wires, and has the same memory footprint.

image.png.e6f427eb530df130fea5f0485ab35210.png

By the way, Darren Nattinger recently held a presentation at GDevConNA 2022 that might be interesting to you. He provides some insights into features of LabVIEW that aren't as stable as one would hope...

 

Link to comment
19 hours ago, LogMAN said:

By the way, Darren Nattinger recently held a presentation at GDevConNA 2022 that might be interesting to you. He provides some insights into features of LabVIEW that aren't as stable as one would hope...

 

That was the best presentation content I've seen from NI for many-a-year.

Cheekily mentioned (almost under his breath) he'd found a way to use the Match Pattern to replace Regex. I too use Match Pattern instead of regex because it beats the hell out of it for performance but it's never as generic as the regex. I need to know more (with code).

Never liked (or used) the Error Constant ( or AF for that matter).

Never used PPL's either but I do use lvlibs with the VI's in an LLB - mainly for ease of distribution rather than load performance. 

The single execution while loop to force clumping was an eye opener. :blink: I've never suffered from that but that's gone in my long term must-know memory.

Xnodes were always too complicated for me so never used them. Interesting he didn't mention XControls. VIM's I liked until they formalised it and then they did not propagate the type downstream (so I couldn't make my "named events"). So don't make any of those anymore.

I agree with his view of text vs VI's. But not for the same reasons. I'm a huge fan of polymorphic VI's with a menu, for example. However. I can read a diagram of VI's I am familiar with (and with good icons) in one glance but I'm not a speed reader. He just doesn't seem to like doing icons whereas I find it a cathartic distraction when stuck on a problem.

My obstinate work flow and dumb preferences seem to insulate me from a lot of the issues that others find. :lol:

Edited by ShaunR
  • Like 2
Link to comment
On 12/1/2022 at 1:14 AM, LogMAN said:

Yes, this makes sense for class members. They should always access the private data cluster directly. Property nodes are only good for callers (and maybe when accessing parent class data).

In the past I also avoided property nodes. Mostly because of stability and performance issues (~2011-2015). Nowadays they appear to be stable and are just easier to read (also, I'm lazy and property nodes don't need icons 😏).

This is probably the best way to get rid of gyno to do it. Read-only and write-only access, however, should still be done with standalone bundle/unbundle. It makes it easier to understand what is going on, avoids unnecessary wires, and has the same memory footprint.

image.png.e6f427eb530df130fea5f0485ab35210.png

By the way, Darren Nattinger recently held a presentation at GDevConNA 2022 that might be interesting to you. He provides some insights into features of LabVIEW that aren't as stable as one would hope...

 

The process you shared and a video both things are easy to understand and helpful too. Thanks!

Edited by PatriciaChing
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.