From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Updating vs. replacing objects (OOP)

Hi, so I have an abstract question somewhat coupled to related more specific question. In the case of OOP objects, I somehow had the preconception that since a programming object represents a real object (more or less), it should generally be persistent and updated via methods. However, I saw an example of the traffic light CLD practice question which used OOP and instead of having a single class for the the intersection, they simply created a new one each time the configuration changed and overwrote the old one (which would hopefully be garbage collected I assume!).

This seemed odd to me if 1 real life object = 1 programming object. However, I can see the advantage of simply recreating the object. It reduces the logical overhead of handling many possible update cases. However, I have not been able to find much to read about doing pros/cons to the two approaches (for programming in general let alone specifically LabVIEW).

 

Where this has me most curious is with regards to device drivers. Currently the experimental setup I work with uses action engines for each of the 3 physical devices involved: signal generator, dependent variable (voltage) setter, and DAQ card (voltage). We step through a range of voltages and do the same signal/DAQ for each step. Presently, I simply call the desired method of each Action engine where needed.

I was wondering if an OOP approach might not be better (for fascillitating a plugin style of different measurement types). My initial idea would just be to let the objects live inside a shift register and pass them to a "Measure" subvi and call their methods from there.

However, after seeing the traffic light example, I wonder if it would make more sense to have an "Experiment" class and create an instance of that each time the Start Measurement button is pressed, pass it to the message handle, and simply run a "Do" method on it.

 

I have a hard time finding examples that address such implementation details, let alone discuss pros and cons. That is understandable given that most complex LabVIEW programs are subject to NDAs, but I get frustrated at the lack of real life examples in comparison to say Python, where I can just go browse highly regarded projects on Github and get a good idea.


I understand this topic/question is a bit nebulous. Hopefully someone understands the point I am trying to get at and has some reading suggestions. Thanks.

0 Kudos
Message 1 of 10
(3,333 Views)

What you're describing (sending a class and using its method) sounds a lot like Actor Framework.

LV OOP is basically glorified clusters, so creating new ones and ditching the old isn't as bad as with reference based classes, the environment will know the cluster has no references and will free the memory. If the class opened e.g. VISA references you can run into some issues ofc.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 2 of 10
(3,312 Views)

@ConnerP wrote:

Hi, so I have an abstract question somewhat coupled to related more specific question. In the case of OOP objects, I somehow had the preconception that since a programming object represents a real object (more or less), it should generally be persistent and updated via methods.


Not sure how representing (more or less) real objects makes you conclude they should be persistent and\or updated via methods. You can make (non-persistent) objects that represent (more or less) real objects. They would still be updated via methods.

 


@ConnerP wrote:

However, I saw an example of the traffic light CLD practice question which used OOP and instead of having a single class for the the intersection, they simply created a new one each time the configuration changed and overwrote the old one (which would hopefully be garbage collected I assume!).


You said it: it's simple. Not always the best way, but if you can get away with it, it's simple. You loose all updated data, data set though methods. Sometimes that's OK, sometimes it's not.

 

There's no garbage collection in LabVIEW. Just lifetime management of data. If you program by wire, the data is simply released from memory when the "wire stops". When you program by reference, this will result in memory leaks unless a close is called. Again, there's no garbage collection in LabVIEW.

 


@ConnerP wrote:

This seemed odd to me if 1 real life object = 1 programming object. However, I can see the advantage of simply recreating the object. It reduces the logical overhead of handling many possible update cases. However, I have not been able to find much to read about doing pros/cons to the two approaches (for programming in general let alone specifically LabVIEW).


Pro: it's simple.

Con: it might not work.

 

It's usually a very pragmatic decision. And it's quite easy to go from one to the other.

 


@ConnerP wrote:

 Where this has me most curious is with regards to device drivers. Currently the experimental setup I work with uses action engines for each of the 3 physical devices involved: signal generator, dependent variable (voltage) setter, and DAQ card (voltage). We step through a range of voltages and do the same signal/DAQ for each step. Presently, I simply call the desired method of each Action engine where needed.


Although AE work with OO, I usually try to keep the programming by wire. AE's (globals basically) can be convenient but they do have downsides. You can put them everywhere. That seems nice, but can become a problem.

 


@ConnerP wrote:

I was wondering if an OOP approach might not be better (for fascillitating a plugin style of different measurement types). 


Yes, OOP is always better Smiley Very Happy.

 

Very suited (but not limited to) facilitating a plugin style of different measurement types

 

@ConnerP wrote:

My initial idea would just be to let the objects live inside a shift register and pass them to a "Measure" subvi and call their methods from there. 

Not sure why you'd need a Measure subVI. simply call their Measure method. If it's an array, you could make a child that contains them all, and when called invokes it's array of it's parents. That means you can make it work with one device, and switch to an array of devices without changing the program. Provided they can store their data in some other object.

 

@ConnerP wrote:

However, after seeing the traffic light example, I wonder if it would make more sense to have an "Experiment" class and create an instance of that each time the Start Measurement button is pressed, pass it to the message handle, and simply run a "Do" method on it.

 

Also an option. Not sure I get all the details, but then that's all up to you.

 

The way you say it makes perfect sense to me. That's a good sign.

 

@ConnerP wrote: 

I have a hard time finding examples that address such implementation details, let alone discuss pros and cons. That is understandable given that most complex LabVIEW programs are subject to NDAs, but I get frustrated at the lack of real life examples in comparison to say Python, where I can just go browse highly regarded projects on Github and get a good idea.

The main think to realize here is that doing analysis and design like you are doing right now, is not limited to LabVIEW. I found it hard myself to even find how to make a program bigger then one file in Python.

 

Even if you find examples in LabVIEW, it's the reasoning that leads to those implementations that is important. And that reasoning is very hard to capture...

 

I'd suggest reading about Analysis and Design, for instance Booch. There's probably a PDF somewhere, but the book is worth having if you're serious about OO.

 

@ConnerP wrote:

I understand this topic/question is a bit nebulous. Hopefully someone understands the point I am trying to get at and has some reading suggestions. Thanks.

Seems to me you already have a healthy interest towards OO. Took me years to switch in LabVIEW, although OO in c++ made perfect sense to me. I just did not see how it would be helpful for my projects, usually limited to 1-4 devices and some file reading\writing. I was wrong. It changed my life, can't even do a CLD or CLA without OO...

Message 3 of 10
(3,307 Views)

You are right that it sounds a lot like actor framework. The thing I don't understand about actor framework though, is if it's main focus is async, where to synchronous device calls fit into it? Especially in the case where one does not what to start measuring before the dependent variable is set.

0 Kudos
Message 4 of 10
(3,305 Views)

wiebe@CARYA wrote:
@ConnerP wrote:

My initial idea would just be to let the objects live inside a shift register and pass them to a "Measure" subvi and call their methods from there. 

Not sure why you'd need a Measure subVI. simply call their Measure method. If it's an array, you could make a child that contains them all, and when called invokes it's array of it's parents. That means you can make it work with one device, and switch to an array of devices without changing the program. Provided they can store their data in some other.

I will try to explain what I meant with some pseudo code. With say Setter_AE, Signal_AE, and DAQ_AE:

 

Signal_AE.enable()
dependent_steps = [x for x in range(0,40)]

for step in dependent_steps:

Setter_AE.set(step)
DAQ_AE.read(n_signals) => Channel wire to analysis

Setter_AE.go_to_default()

Signal_AE.stop()

I currently have this in a Measure subvi and then channel it into an Analysis subvi, which in the end passes all the analyzed data into a save subvi. These 3 subvis exist in the "Start Measurement" case of the QMH. Obviously there is some more logic involved than what is shown and that is why I mentioned having it inside a subvi.

Also thank you for the book recommendation. That looks like a good one. 720 pages... Talk about a tome!

0 Kudos
Message 5 of 10
(3,300 Views)

@ConnerP wrote:

You are right that it sounds a lot like actor framework.


If you have a hammer, everything looks like a nail.

 


@ConnerP wrote:

The thing I don't understand about actor framework though, is if it's main focus is async, where to synchronous device calls fit into it? 


Exactly.

 

You could use actors. It would be impossible to make anything non-trivial without something like an actor (actor=parallel process).

 

But if you make everything an actor, synchronizing them becomes a problem. A problem you don't have without AF. So I don't make everything an actor, and therefore don't use AF. Guess maybe there is a balance somewhere...

 

Lots of people like AF. Suit yourself. It might not be the best introduction to OO, it's not the easiest material, IMHO.

 


@ConnerP wrote:

Especially in the case where one does not what to start measuring before the dependent variable is set.


You can bring those actors to life at any moment (or so I assume). So you can create those actors with the dependent variables dynamically when start is pressed. Some problems are just much simpler without actors.

0 Kudos
Message 6 of 10
(3,293 Views)

wiebe@CARYA,

Absolutely. Actor framework has never my intended direction for this. And as you say, non-trivial things take on actor characteristics . If there were a clear cut solution to these problems though, a computer could do it and we would be out of jobs. Thank god for difficult tasks I suppose right?

Message 7 of 10
(3,282 Views)

@ConnerP wrote:

wiebe@CARYA wrote:
@ConnerP wrote:

My initial idea would just be to let the objects live inside a shift register and pass them to a "Measure" subvi and call their methods from there. 

Not sure why you'd need a Measure subVI. simply call their Measure method. If it's an array, you could make a child that contains them all, and when called invokes it's array of it's parents. That means you can make it work with one device, and switch to an array of devices without changing the program. Provided they can store their data in some other.

I will try to explain what I meant with some pseudo code. With say Setter_AE, Signal_AE, and DAQ_AE:

 

Signal_AE.enable()
dependent_steps = [x for x in range(0,40)]

for step in dependent_steps:

Setter_AE.set(step)
DAQ_AE.read(n_signals) => Channel wire to analysis

Setter_AE.go_to_default()

Signal_AE.stop()

I currently have this in a Measure subvi and then channel it into an Analysis subvi, which in the end passes all the analyzed data into a save subvi. These 3 subvis exist in the "Start Measurement" case of the QMH. Obviously there is some more logic involved than what is shown and that is why I mentioned having it inside a subvi.

Also thank you for the book recommendation. That looks like a good one. 720 pages... Talk about a tome!


Those AE just make things more difficult. As you've mentioned, use shift register holding the object. It's conceptually so much easier.

 

Of course, nothing wrong with making a sub VI for doing more advances steps. Preferably a VI in a suitable class object, called "measurement" or something like that. That class\object could either contain the devices, or use the devices. E.g. have them in their private data, or get them as VI input when needed. This might seem hard at first, but without OO, you don't really have a choice.

 

I'd really would advice against using AE in such a class. But you can if you want to (if only as a transition state towards a good design). Consider what happens when you want two measurement objects... By wire: not a problem. AE: conflict...

 

0 Kudos
Message 8 of 10
(3,277 Views)

@ConnerP wrote:

Also thank you for the book recommendation. That looks like a good one. 720 pages... Talk about a tome!


 The 3rd edition has a few hundred pages about UML. Interesting, but honestly you won't need it all. (You can buy the 2nd edition without UML stuff for <5$)

 

It also has a few hundred pages with case studies. Not all of them are relevant for us.

 

The first few chapters are what it's all about, establishing a OO moral if you will. What's good, what's bad, and why.

 

A more practical "what's bad and why" you can find in Holub on Patterns.

0 Kudos
Message 9 of 10
(3,276 Views)

@ConnerP wrote:

Thank god for difficult tasks I suppose right?


Definitely what's keeping me hooked.

Message 10 of 10
(3,271 Views)