Jump to content

LVOOP constant with non-default parent values?


Recommended Posts

I have a LVOOP project where I have a parent class with all of the data required and many child classes which have custom accessory to this data but no data of their own (with child-relevant parsing built-in).

When I drop a child constant, since I have no actual data within the child class, I cannot have the class default to different data than the parent and the parent always has default data. My question is how I can create a child object constant with parent data corresponding to something else than the default values?

Shane

Link to comment

Hi Shoneill

One way could be to create a constructor for the Child class that sets the data to the default values you want.

post-10325-090679800 1280136680_thumb.pn

Well, yeah I know (it's what I'm doing at the moment) that but it would be so nice to be able to just drop a constant on the BD and have it run from there without requiring a constructor....

At the moment I have a function to create the object with the appropriate values being set within.

Shane

Link to comment

I think it is preferable to initialize the values of the object explicitly (not technically a constructor). This is important so that someone can understand the code. (One can't tell by looking at an object constant what it's values are. OK, one can work this out if the values are the defaults, but even in this instance I don't think it's good coding practice to use object constants this way.) If the values come from a file one can change the values without changing the code (protecting for variations).

Link to comment

I don't think it's good coding practice to use object constants this way.

I agree with Paul. I've used non-default object constants in the past and in the end I thought they were more trouble than they were worth.

My question is, why do you want the child to have non-default values and how are those values determined? If the values are fixed at edit time, you might be able to change your structure in a way that allows child classes to use default values.

Link to comment

I agree with Paul. I've used non-default object constants in the past and in the end I thought they were more trouble than they were worth.

I haven't used them in coding, but know you can do it. I can imagine it would be a nightmare to track and make an edit in a large app.

I think it is preferable to initialize the values of the object explicitly (not technically a constructor).

post-10325-032397900 1280192983_thumb.pn

Tomi showed me the above here and I have been using it ever since

It does not need a Class input (that is optional but can be used by child classes that need to call it)

The only thing I can think of is that if you have a plugin architecture and you need to call this you will need to wrap it in a DD VI anyways.

Is it not a constructor? Well maybe not a real one, but close enough in a LabVIEW context?

Please discuss - does anyone do anything similar, different etc...?

Link to comment

The feature requested in the original post does not exist in LabVIEW. We've talked about some sort of specially tagged VI that runs once when the class is reserved to set the default value that will be used for the rest of that run (and which every control/constant that is using the default default value would therefore use), but it hasn't ever been implemented. Since there is no central copy of the default value on RT systems, that would be hard to implement there.

Link to comment

Tomi showed me the above here and I have been using it ever since

Heh heh... "fructarted." That still made me laugh.

(I needed that today. Thanks Ben!)

Please discuss - does anyone do anything similar, different etc...?

Interesting you should bring this up. I've kind of waffled back and forth between including and not including a class input terminal on my constructors. I had finally settled on not including it in the last month or two. Last week I ran into a situation where I *had* to have a dyn disp input on my constructor. I've been meaning to write it up and post it to get feedback from the experts.

Link to comment

Interesting you should bring this up. I've kind of waffled back and forth between including and not including a class input terminal on my constructors. I had finally settled on not including it in the last month or two. Last week I ran into a situation where I *had* to have a dyn disp input on my constructor. I've been meaning to write it up and post it to get feedback from the experts.

(Just to clarify the above example has Static connections with the class Input as optional)

Link to comment

So the bottom line is that it doesn't work, it shouldn't work and it won't work....:nono:

OK. Just needed to hear that so that I can accept the "constructor" way of life. :yes:

Thanks

Shane

PS Just to clarify. I wasn't looking for multiple default valeus for a single class but a different default value for each class. I see how multiple constants for a single class with different default values would be horrible, but that's not what I was looking for. I only want each child class to have its own different default values. This would have worked with the special tagged VI AQ mentioned....

Edited by shoneill
Link to comment

The feature requested in the original post does not exist in LabVIEW. We've talked about some sort of specially tagged VI that runs once when the class is reserved to set the default value that will be used for the rest of that run (and which every control/constant that is using the default default value would therefore use), but it hasn't ever been implemented. Since there is no central copy of the default value on RT systems, that would be hard to implement there.

I like the sound of this feature being integrated.

However, it would not help if your constructor required inputs???

Thinking out loud...

  • Would it be possible to flag a method VI as a constructor and somehow check that there are no constants on the BD (sounds tricky)
  • What about when you drag and drop the class/control onto a BD it could automatically drop the flagged constructor VI instead?

Link to comment

I like the sound of this feature being integrated.

However, it would not help if your constructor required inputs???

Thinking out loud...

  • Would it be possible to flag a method VI as a constructor and somehow check that there are no constants on the BD (sounds tricky)
  • What about when you drag and drop the class/control onto a BD it could automatically drop the flagged constructor VI instead?

No go. You need a *constant* value, something that can be set once and only once in the entire run of the app. It cannot take *any* inputs and its only output is the class value. All of this is conception only -- since we started deploying on RT, as I said, I'm not sure that the centralized bottleneck exists that would let us make this work. It's messy even to think about.

There is one option that hasn't been discussed in this thread: Suppose my parent class has a field "Color" and a "Get Color.vi" and a "Set Color.vi" both of which are dynamic dispatch. The parent class implementation of Get and Set just returns the color field or sets it (respectively). The child class has a boolean field "Has been set?". It overrides "Set Color.vi" to set the boolean to True and then calls the parent version to set the field. The "Get Color.vi" override checks 'has been set?'... if it is True, it calls the parent to retrieve the value. If the value is false, it returns its own local constant value.

This avoids the need for a constructor, it makes block diagram constants and controls behave exactly as requested in the original post. It is more effort than a programmer might wish to deal with.

Link to comment

I'm assuming you want different parent class values for each child class because you have parent class methods that need to do slightly different things depending on which child class instance is on the wire at runtime.

There is one option that hasn't been discussed in this thread:

Here's a similar option I've done that also eliminates the constructor...

Since the color constant is consistent across all instances of the class, use the Must Override option to "hook" into the constant for each child class. Give the parent class a dyn disp Get Color method and mark it as Must Override, but don't create a Color field in the parent class. In the child class, you can either:

a) Put the color constant directly on the overridden Get Color method, or

b) Make the color constant a class field and use a regular accessor method.

I've done it both ways. B is easier to maintain if you have several constant hooks as all the constant values are centralized. I don't know if it makes a difference in execution.

I used this technique in a situation where I had a fairly complex process that had only slight variations, such as the name of a table to store the end result. I ended up creating a unique child class for storing data in each table--about 20 in all. Looking back I think this made the code more complicated than it needed to be. Faced with the same situation today I would use a parent class constructor that took all the immutable data (such as table name) as inputs, create the necessary object at run time, and scrap the child classes completely.

(Edit - This technique is kind of along the lines of the Template pattern, except instead of replacing algorithm steps you're just replacing algorithm constants.)

Link to comment
  • 2 months later...

Ideally you wouldn't inherit from anything with an Initialize method. You would create an abstract parent class, move all existing methods and data up to that class (except for the Initialize), and your new class would be a sibling class, and thus able to have its own initialize. This is ideal because it maximizes flexibility for future development since each actual concrete class can evolve independently. Sometimes it isn't possible to make this mutation (especially if you need the LV auto-mutation of flattened strings to work for values saved in files or because you don't own the parent class), but if you can, that's probably the best route.

When you can't do that, have a protected InitCore.vi that takes a dyn disp input and a public "Init X.vi" where X is the name of the class that does not have the class input. The descendant class would create its own "Init Y.vi", and it would call InitCore.vi to get the parent segment initialized.

  • Like 1
Link to comment

Did you ever decide on the right thing to do here?

Despite my frequent visits to the soapbox and carrying on about a specific topic, there is no universal "right" thing to do. It all depends on your specific needs, priorities, and capabilities. I tend to follow AQ's second suggestion. Each of my class' Create methods are appended with the class name--Create MyParentClass.vi, Create MyChildClass1.vi, etc.--and the class output is static dispatch. That avoids potential name collisions in the inheritance tree yet allows the flexibility to initialize child classes with different data.

You would create an abstract parent class, move all existing methods and data up to that class (except for the Initialize), and your new class would be a sibling class, and thus able to have its own initialize. This is ideal because it maximizes flexibility for future development since each actual concrete class can evolve independently. Sometimes it isn't possible to make this mutation (especially if you need the LV auto-mutation of flattened strings to work for values saved in files or because you don't own the parent class), but if you can, that's probably the best route.

I used to take the time to create abstract parent classes, but I spent too much time writing preventive error handling code to handle situations where a parent object is unintentionally travelling on the wire. I also found it a bit cumbersome to work with during the initial development process when I'm making lots of changes to class methods since every change required modifying two classes instead of just one. These days my first step is to implement one of the planned child classes as the concrete parent. Other planned child classes inherit from the concrete parent. If the need for an abstract parent arises later it's not difficult to create one and reassign the inheritance to have all the children point to the new abstract parent. (Of course, deciding when the concrete parent should be converted to an abstract parent is one of those decisions that only comes with experience.)

The one time when I will start with an abstract parent class is when I'm creating a code module that needs to define a class, but other code modules will be creating concrete child classes to pass to the first module. In other words, one module is exposing an interface that will be implemented by another module. When my entire class hierarchy is contained in a single code module the extra overhead and complexity of an abstract parent usually wasn't worth it to me. YMMV.

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.