Jump to content

Methods with base class interface


Recommended Posts

Hi,

 

I was thinking about a problem, that I experiance often with arrays of different class objects. I have a approach to solve this convenient, but would like to get oppinions, if I am getting drawbacks by this I don't see.

So it would be nice, if I could get some feedback on this.

 

Here the problem:

Arrays of mixed classes are of type of base class. When extracting an object and appying a method of the inherited class, a to more specific class conversion has to be done before wiring. This is really a pain when to be done a lot of times. I thought now why not use the base clase as interface in the inherited class and do the to more specific class conversion inside. Then wiring is much easier.

 

Please see example.

 

Thanks

 

Dermot

ObjectInterfaceProblem.zip

Link to comment

Here are a couple ideas.

 

Do all vehicles have a 'Capacity'?  If so, you might consider having a method or property with dynamic dispatch terminals that returns Capacity.  It would be defined in Vehicle.lvclass.  Car and Truck (Motorcycle, Boat, etc.) would override to supply their respective capacity if they had any.  By default, Vehicle.Capacity could return 0.

 

Also, consider creating a Collection class that holds the array (or some container) of Objects.  Methods like Add would allow you to build the Collection up.  GetAtIndex would return the Object.  Adding an LVObject terminal to GetAtIndex and wiring that into the 'target object' terminal of a Preserve Run-Time Class node will encapsulate those 'To More Specific' nodes and still give you design time type safety. Still, a the PRTC node will error at run-time if you try to make a truck into a car.

 

My development machine is not on the network so I cannot supply an example at the moment.  Let me know if that would be valuable and I can try tonight.

 

-Kurt

Link to comment

My general recommendation is at the application design layer to put items into an array collection only when you intend to use an array interface to the items in that collection (i.e., iterate over the items in the array using an interface defined on the class of the array--the parent class, Vehicle, in your example).

 

Now it may make sense in your example for the parent to have this definition.  (In your example, then, each Vehicle would have a capacity.  A Vehicle child object would define a nonzero value, while a Car object would define a zero value.)  In this solution capacity would be an attribute of Vehicle, although dynamic dispatch methods on the child classes may define the values, calling a public accessor method on Vehicle.

 

Note that it is perfectly logical to define static methods on Truck and Car for use before adding them to the collection.

Link to comment

Thank you very much for the replies.

 

The collection is a concept I also use and also think it has many benefits.

 

But here I actually was mor interested in the point of using vehicle class as interface on a truck method. This to be able to not have to do "To mor specific Class) conversion in the places wher truck class is needed. The conversion is done inside.

 



here an image

TruckMethod.zip

Link to comment

Yup, I got that.  Not happy with it, though I do not have the CompSci background to say exactly why.

 

One thing that makes me uncomfortable is that as a developer using this API, I would not expect it to error if I asked a simple question like 'what is your capacity?'.  Or more importantly, why I am allowed to ask this question on an arbitrary vehicle if it is truly not a valid request.

 

That aside, what if I have a chain of inquiries to do that are specific to a truck: capacity, # of axles, gross vehicle weight, etc.  Do I create a static method that encapsulates the To More Specific node (with the call to the property method) and chain these together?  Seems that it is adding unnecessary overhead on the repeat To More Specific call, error trapping, etc.

 

As an alternate to a full collection class, even a simple function that accepts an array of vehicles (or even LVObjects), an index and a target class (constant of Truck in your example) that uses the index to access the array and passes the value to a PRTC node returning a properly 'cast' Truck if the index was a Truck.  Otherwise it returns an error.  The error would be a 'natural' result for this type of function because the developer could anticipate the request might not be valid.  This approach encapsulates the cast in an expected location, 'cleans up' your diagram and maintains design time type safety.

 

Just my opinion, but then that is what you were asking for. :yes:

 

Kurt

Link to comment

Dermot,

 

I think the approach you are following is not the way to go.

 

If your application API deals with Vehicles, use an array of Vehicle.  If the API expects Trucks and Cars, instead of an array of Vehicle, use a cluster containing a Truck and a Car.

 

Paul

Link to comment

Kurt and Paul,

 

well, the reason I want to cut out the To more specific class conversion is I am creating an API, that uses LabVIEW classes, but it is targeted to the normal LabVIEW user, which might never have used LabVIEW classes.

I know I will be in a support hell, if I dont find a way to avoid the to more specific class conversion.

If I put it in a collection class, then this class needs to know all existing classes. And if a new class is added, also the collection class has to be updated. This doesnt work for me, because users can also add their own classes.

 

The vehicle, truck, car code was just a simplified code to represent the problem.

In my case it is about a modular IO system. So I have an array of ModuleClassBase and inherited Classes ModuleAnalogIn, ModuleAnalogOut etc.

I can get the module by index from the array and use an aproriate method like write outputs or read inputs. But coming from the array a to more specific conversion has to be done before passing it into the read or write method.

This is going to be too much for a lot of LabVIEW users :-)

 

Cheers

Link to comment

If done right, the collection class should not know anything about the classes it contains.  Though not using a class, in the attached example I have included a function that takes an array of vehicles and returns a properly cast vehicle (vehicle, truck or car).  It will error if you index a car and expect a truck.  You could actually make the icon look like the Index Array icon.  Anyway it is an example of the use of the Preserve Run-Time Class node which often confuses the new OOP user.

 

I do agree with Paul in that once the entities are in an array they should be considered homogeneous - as in all vehicles.  I should be able to wire the output of the array to any method supported by the base class.  I can deal with an array of vehicles that are all trucks and require the cast.  But a collection of cars and trucks and treating them all like trucks is not a good design.

 

I understand your dilemma with those unfamiliar with OOP.  I think though, you are setting up the user for unexpected runtime errors. In your real life example, what happens when I wire an AnalogInput to a write byte method?

 

It is Friday night and I am about done with a Long Trail Limbo IPA (delicious by the way) so this is pretty much all I can add for now.

 

-Kurt 

ObjectInterfaceProblem_ALT.zip

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.