LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Best practice for saving and recalling objects from disk?

I've been using the OOP features of LabVIEW for various projects lately and one thing that I struggle with is a clean method to save and recall objects.

 

Most of my design schemes have consisted of a commanding objects which holds a collection of worker objects.  Its a pretty simple model, but seems to work for some design problems.  The commander and my interface talk to each other and the commander sends orders to his minions in order to get things done.  For example, one parrent class might be called "Data Device Collection" and it has a property that is an array of "Data Device" objects.

 

The Data Device object is a parent class and its children consist of various data devices such as "DAQmx Device", "O-Scope Device", "RS-232 Device", etc.

 

When it comes to saving and loading data, the commanding class's "Save" or "Load" routine is called and at that time all of the minions' settings are saved or recalled from disk.

 

My save routine is more-or-less straight forward, although it still requires an overwriting "Save" and "Load" vi.  Here is an example:

Save Routine.png

 

It isn't too bad in that it is pretty straight forward and simple and there also would be no changes to this if the data structure of the class changed at all.  It also can save more generalized settings from it's parrent's class which is also a good feature.  What I don't like is that it looks essentially the same for each child class, but I'm at a loss on an effective way to move the handling of the save routing into the parent class.

 

The load routine is more problematic for me.  Here is an example:

Load Routine.png

 

Again, the desirability of moving this into the parent class would be awesome.  But the biggest complaint here is that I can't maintain my dynamic dispatch input-output requirements because the object that I load is strictly typed.  Instead I have to rely on reading the information from the loaded object and then writing that information to the object that exists on the dynamic dispatch wire.  I also dislike that unlike my Save Routine, I will need to modify this VI if my data structure of my object changes.

 

Anyway, any input and insight would be great.  I'm really tired of writing these same VIs over-and-over-and-over again, and am after a better way to take care of this in the parent class by keeping the code generalized but still maintain the ability to bring back the saved parameters of each of the children classes.

 

Thanks for your time.

0 Kudos
Message 1 of 11
(5,657 Views)

Dang, I was hoping there would be some input.  *bump* ... :S

0 Kudos
Message 2 of 11
(5,601 Views)

Bear with me here, as I don't have a lot of LVOOP experience yet but I have some ideas, and am hoping maybe we'll both learn something from some discussion.

 

I can't tell exactly what you're doing in the parent class' version of the Load and Save.  Are you saving two separate files - one for the parent class, and one for the child class?  If so, is there some reason you can't simply only the child class?  That should include all the associated parent data.  If that's not what's going on, perhaps you could elaborate a little bit more.

0 Kudos
Message 3 of 11
(5,589 Views)

Yeah, sure.  Here are the Save and Load Settings from the parent class.

 

Parent Class Save Settings.png

 

Parent Class Load Settings.png

 

 

 

 

0 Kudos
Message 4 of 11
(5,548 Views)

I have abondoned the classes that took advantage of the ability to write and restore a class from disk since it was hit by a change in LVOOP that I was very disapointed to find.

 

My current go-around with LVOOP save restore uses a "Save Thyself" approach where the obects know what they need so they get their internal data from file themsleves.

 

It has hlped my code more than I could forsee at first becuase it removed the requirment that the user of the classes know what they need and can give it to them. Pushing it down into the claass itself lets me init a DAQ class with the same parent method I use for GPIB Serial or whatever.

 

That is all I can add,

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 5 of 11
(5,540 Views)

I'm with Ben. Don't rely on the current ability to serialize an object. Create a save method and implement some form of data persistence there. If you modify your class you might be disappointed when you cannot load objects you previously saved. It mostly works but as soon as you reset the version information in the class, you can no longer load the old objects. This is fine if you know how to avoid resetting the history. One thing that will do this is if you move the class into or out of a library. It becomes a new class with version 1.0.0 and it no longer recognizes the old objects.

 

[Edit:  I see that you are just writing to a binary file. I'm not sure you can load older objects anyway using that method but I have never tried it.]

 

This will not help you right now but there are plans for a nice robust API for saving objects.

=====================
LabVIEW 2012


Message 6 of 11
(5,532 Views)

There's either a hidden function or something I'm not understanding.  Why does it appear that the data type input to Read from Binary File is a different type (different wire, anyway) than the data out?

0 Kudos
Message 7 of 11
(5,511 Views)

@nathand wrote:

There's either a hidden function or something I'm not understanding.  Why does it appear that the data type input to Read from Binary File is a different type (different wire, anyway) than the data out?


Because there is a difference between dynamic object data types ("dynamic dispatch terminals") and strictly typed objects.  In this instance, the Read from Binary will only return strictly typed data and that is why the wire changes.  That is part of my problem and why I have to use my accessor methods to read the data from the strictly typed object that is returned from Read from Binary and then write to my dynamic object.

0 Kudos
Message 8 of 11
(5,498 Views)

@Ben wrote:

I have abondoned the classes that took advantage of the ability to write and restore a class from disk since it was hit by a change in LVOOP that I was very disapointed to find.

 

My current go-around with LVOOP save restore uses a "Save Thyself" approach where the obects know what they need so they get their internal data from file themsleves.

 

It has hlped my code more than I could forsee at first becuase it removed the requirment that the user of the classes know what they need and can give it to them. Pushing it down into the claass itself lets me init a DAQ class with the same parent method I use for GPIB Serial or whatever.

 

That is all I can add,

 

Ben


Essentially that is what I am doing, each object runs its "Save Thyself" method (what I am calling "Save Settings").

 

If my object data changes, I may have a hard time reading my previously saved objects, but I'm less concerned with this right now.  My objects aren't necessarily data, more like setting information.

0 Kudos
Message 9 of 11
(5,497 Views)

@Nickerbocker wrote:

Because there is a difference between dynamic object data types ("dynamic dispatch terminals") and strictly typed objects.  In this instance, the Read from Binary will only return strictly typed data and that is why the wire changes.  That is part of my problem and why I have to use my accessor methods to read the data from the strictly typed object that is returned from Read from Binary and then write to my dynamic object.


Ah, got it (I warned you I don't have too much experience with this), your situation is starting to make sense to me.  I haven't tried this, and don't have a project set up that would allow me to try it easily, but does the Read from Binary File read the child class data and return it as the parent class?  If so, can you use "Preserve Run-Time Class" to get the child class?

0 Kudos
Message 10 of 11
(5,491 Views)