LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

OOP - Bypass Dynamic dispatch methods from parent class method

Solved!
Go to solution

Introduction


I am currently creating VIs for interfacing with a specific type of hardware via RS-232, let's say that the hardware is a Laser. I assume I will always have to interface with some kind of laser (let's say I now have two different models) from my main VI, so I'm planning to make it easy me in the future to accommodate more Laser models by designing my interface as a base class, with one subclass for each laser model, inheriting from the base class. One of my main requirements is to also make it easy to change laser model dynamically, after my main VI will have started. To do so, I plan to make use of LabVIEW's capability of class polymorphism.

 

So, I begin by creating a laser_base class. This is the class which will include all the abstract functionality and attributes I want all the laser models to have. It will feature VIs/methods such as fire_laser, stop_laser etc. Let's say it also has an is_enabled boolean attribute, which determines whether the laser is enabled or not.

mpliax_3-1591968854475.png

 

To be able to change laser models on the fly, I create a laser_model_typecast VI, as follows:

laser_typecast.png

This is where class polymorphism comes into play, as I understand. No matter what kind of child class I typecast to, they all have a common denominator (laser_base). Dynamic Dispatch VIs will be used later in order to choose at run-time which model-specific VI to call, depending on the laser model.

 

Since I expect all of the laser models to have the same functionality (with different implementation under the hood), I create a new VI from Dynamic Dispatch template named fire_laser, which I incorporate into my laser_base class. This does nothing, just sits there and specifies that this functionality should exist, one way or another.

fire_laser_base.png

 

To force this functionality into existence, I configure the laser_base class to Require descendant classes to override this VI (fire_laser) and to also invoke the parent method. Each time I create a new subclass for a new laser model, I will be forced to also override this method. That's good for future me, which will definitely have forgotten what the hell he had done some years before.

mpliax_1-1591968507297.png

I proceed to override the fire_laser VI in each subclass, adding the model-specific functionality I need for it to operate. I am now at the stage where I have the functionality I need to create my main VI which will actually control the laser.

mpliax_2-1591968708299.png

 

So far so good. I edit my main.vi as follows:

main.png

I create a constant for the laser_base (not really required), I typecast to the laser model I want, I disable/enable the laser and I proceed to fire.

 

The actual question:


As you've noticed, I've not yet taken advantage of the is_enabled boolean, and this is where my actual problem arises.

I need to be able to disable/enable all and any future child classes (laser models) methods using the is_enabled boolean in the parent class.

Ideally, setting the is_enabled boolean in the parent class disables all of the VI methods in all subclasses without too much fuss.

 

What I've tried:

 

The only way I can think of right now (considering how I chose to structure my code) is to go inside each subclass VI and put all the functionality inside a case structure wired to the is_enabled control so that it is only run if is_enabled is true, like so:

 

fire_laser_override.png

This is the fire_laser VI which I've overridden for laser_type_a. The broken VI is the Call Parent Method VI (which appears normally in my code).

 

I can also think of no functionality which I can put inside the parent method that can override the subclass VI, since the model-specific functionality will always be called, no matter what the parent does.

 

I'm also using LabVIEW 2010, if it makes any difference.

 

I've stumbled upon many different forum topics here, but I could not find anything similar. Most of my questions have been answered but I cannot find a satisfying approach to deal with this one.

 

Thanks a lot in advance.

 

Edit: added project zip for reference.

Edit 2: clarified question.

0 Kudos
Message 1 of 7
(2,591 Views)

Your stuff is broken (missing items, and apparently misnamed items).

Use a property node to access the "enabled" bit instead of calling "Read is_enabled.vi"

"If you weren't supposed to push it, it wouldn't be a button."
0 Kudos
Message 2 of 7
(2,546 Views)
Solution
Accepted by mpliax

There is a way to do what you're looking for but it's not *quite* as easy as just throwing in a checkbox, but it's not hard at all. You just need to make a static wrapper.

 

First, you don't need to force descendants to call parent node.

 

Second, create a *static* VI for your laser_base class called fire_laser. Create a separate, *private scope* dynamic dispatch method called fire_laser_core.

 

fire_laser will simply check the Enabled boolean, and if it's True, call fire_laser_core. fire_laser_core is where you implement the actual ability to fire the laser in your subclasses. Since the top-level fire_laser_core doesn't actually do anything, you don't need the call parent method node.

 

By making fire_laser_core private, you ensure that the end user cannot call it without calling its wrapper function fire_laser. You CAN fire the laser within another child method (as the check isn't implemented in the fire_laser_core VI) so it's not totally bulletproof, but it's better than nothing, and it DOES prevent the end user from firing the laser.

Message 3 of 7
(2,537 Views)

@BertMcMahan wrote:

Second, create a *static* VI for your laser_base class called fire_laser. Create a separate, *private scope* dynamic dispatch method called fire_laser_core.


Dynamic Dispatch VIs cannot be Private scope.  You actually want Protected scope.  Protected scope will allow any children to use the VI.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 4 of 7
(2,528 Views)

Dangit, I couldn't remember which one it was and I didn't have LV open. Yes, Protected scope for this. Thanks.

Message 5 of 7
(2,513 Views)

 


@BertMcMahan wrote:

There is a way to do what you're looking for but it's not *quite* as easy as just throwing in a checkbox, but it's not hard at all. You just need

to make a static wrapper.

Thanks for this idea! Sounds good and I'll get to try it out soon. 🙂

 

 


By making fire_laser_core protected, you ensure that the end user cannot call it without calling its wrapper function fire_laser. You CAN fire the laser within another child method (as the check isn't implemented in the fire_laser_core VI) so it's not totally bulletproof, but it's better than nothing, and it DOES prevent the end user from firing the laser.

This could also prove useful under certain circumstances. I believe that this is the best way to approach this! This also solves another matter I had in mind: No matter what, I wanted to display a message while the laser is starting to fire, preferably in a modal window, so that all other controls are temporarily disabled. By putting the message in the original fire_laser VI in the laser_base class, the message was only displayed for the one instant it took to call the parent method. Using your way, I can display the message in the fire_laser method, while the fire_laser_core is running.

 

That's great and I have to admit I'm a bit excited to see this in action.

0 Kudos
Message 6 of 7
(2,462 Views)

Thanks to you both! I can't believe how easy it was (and why I hadn't thought of it before), even though I had to make a wrapper for many other methods I already had. I was wishing I wouldn't have to make an extra VI call but this way is much cleaner and maintainable.

0 Kudos
Message 7 of 7
(2,375 Views)