Jump to content

Inheriting vs. Containing


Recommended Posts

I saw a comment by Aristos Queue a different thread (see Post #11 in http://forums.lavag.org/I-want-polymorphic...lass-t8853.html) which I want to discuss further

QUOTE

Neither C++ nor Java allows you to cast a value of the parent class as a child class. ...

Let me go one step further and say that in the vast majority of cases where you might think you want this ability, you've actually got the wrong relationship between the classes. Instead of inheritance, you should have containment. The "child" class should actually contain as a private data member an instance of "parent" instead of one inheriting from the other. Thus the parent data gets constructed at time N and at time N+1 the child data gets constructed with that parent data as a data member.

I am trying to make some objects which have some shared properties with some different behaviors. For example I have parent class 'vehicle', and child classes 'car' and 'truck'. I don't want to strain the analogy too far, so I'll get real and say that I have DLL code which needs to open a session, common to all vehicles, and then I have different methods for car and truck which could be dynamically dispatched depending on the object on the wire.

On opening the session, I get a handle, which needs to be used by all other methods in the child classes. In my first attempt, the session was in the parent private data, so I would need a parent accessor subvi call in every child call just to get the handle value. I guess that's not a deal-breaker, but it just seems like an unwieldy pattern. It would be easier to just include the handle in each of the private data clusters for the children, but that chips away at the whole point of an object-oriented design, which is to avoid duplicating common code and data structures.

So on re-reading the quoted text, it seems like I could make the parent data structure include the handle, and then stuff the parent private data into the child class so that it is available where the code needs it.

Does that make sense? Should the child class still inherit from the parent class? Maybe my parent class is really gasoline, used by car and truck, rather than vehicle, the generic type of car and truck. I'm not sure how I can really tell the difference.

Link to comment

Hi,

First about inheritance vs. containment. I like to use inheritance in the way that objects from child classes are exchangable. To do this the public methods of the parent class must make sence and be possible to override in the child classes. It is unlikely that this will work if the classes in the inheritance hierarchy represents totally different "things". Truck inheriting from Vechicle would make sence since a truck "is-a" vehicle. But the Truck inheriting from Gasoline seems weird. And Vehiecle inheriting from Gasoline or vice versa also seems weird. Those classes are different abstractions.

About the session data field in the Vehicle parent class. I don't know what kind of code you need to handle the session but let's assume you put it in a separate class to use containment. Then you let Vehicle contain this class in one data field. This may be good from a design perspective (I couldn't tell without knowing more about what you do) but it doesn't solve the issue that you find annoying, i.e. child classes has to use a get method from the parent class to read out the object... back to square one:-).

Here is one way of solving the case with scenarios repeating in child class methods.

For each dynamic dispath VI in the parent class create a static "mirror" method. The static method should be public and work like a "macro", in this case GetSession-call the DynamicDispath VI to do the job-CloseSession.

Let's say you like the vehicle class to have the dynamic dispatch vi "StartEngine". Make this VI protected and call it StartEngineImp. Then create a static method and name it StartEngine (in the Vehicle class). In StartEngine you first read out the session, then wire it to StartEngineImp, then close the session (if needed).

Child classes Truck/Car should create overrides for StartEngineImp.

This scenarion will double the number of methods in the parent class but you will not have to repeat scenarios in child class methods. If it is worth it only you can tell.

There may very well be smarter ways of doing this, please let us know. I haven't really tried it in LabVIEW but I believe it should work.

Link to comment

QUOTE(Jan Klasson @ Sep 14 2007, 03:04 AM)

Yes, I was trying to make that point. If both of my vehicles use gasoline, should it seems like it should be provided by (a property of) the parent class, and yet, since there is no protected data, only private data, the vehicles can't use it.

QUOTE(Jan Klasson @ Sep 14 2007, 03:04 AM)

About the session data field in the Vehicle parent class. I don't know what kind of code you need to handle the session but let's assume you put it in a separate class to use containment. Then you let Vehicle contain this class in one data field. This may be good from a design perspective (I couldn't tell without knowing more about what you do) but it doesn't solve the issue that you find annoying, i.e. child classes has to use a get method from the parent class to read out the object... back to square one:-).

Yes, I tried it just after posting and realized it doesn't work. The child can't use the private data from a class it contains. That makes plenty of sense, but I have to find a different solution. Maybe I am just allergic to lots of accessor methods and I should get over it, but I see the need for many of tham as an impediment to productivity.

QUOTE(Jan Klasson @ Sep 14 2007, 03:04 AM)

Here is one way of solving the case with scenarios repeating in child class methods.

For each dynamic dispath VI in the parent class create a static "mirror" method. The static method should be public and work like a "macro", in this case GetSession-call the DynamicDispath VI to do the job-CloseSession.

...

This scenarion will double the number of methods in the parent class but you will not have to repeat scenarios in child class methods. If it is worth it only you can tell.

I think you are right. Your method is probably a sensible way to go. It sure doesn't make a LabVOOP design any easier to implement when protected data would give you this for free.

I actually solved my DLL problem by sticking to one class, and making similar methods for the two types of 'children' which I didn't bother to implement with objects.

Thanks for your response. I would love to keep the discussion going because I feel like this situation will keep recurring.

Link to comment

Actually Endevos GOOP 3 class architecture provides protected data which is what you want. It is based on the lvclass and adds the by-reference model.

You can read about GOOP 3 in the GOOP Development Suite tools manual on-line:

http://www.endevo.se/files/downloads/products/gds/

Read the GOOP 3 provider section.

Read more about the tool here:

http://www.endevo.se/content/view/109/107/lang,en/

Download free trial here:

http://www.endevo.se/content/view/18/20/lang,en/

Also, the GOOP 3 is currently not included in the Community Edition but when we (very, very soon...) release the UML Architect edition we will add GOOP 3 to the Community Edition aswell.

Sorry for the plug, but I thougth it was informative since you clearly want protected data.

Thanks,

Jan

Link to comment

QUOTE(Jan Klasson @ Sep 14 2007, 12:09 PM)

Actually Endevos GOOP 3 class architecture provides protected data which is what you want. It is based on the lvclass and adds the by-reference model.

...

Sorry for the plug, but I thougth it was informative since you clearly want protected data.

Hi Jan: Thanks for the tip. I will check out the Endevo toolkit. I have heard so much about it and I am glad to hear it could solve some problems. I think the by-reference objects will help with some other constructs I am working on. Does the toolkit also help with by-value classes?

However, I do still wonder whether NI will move toward access of protected data. It seems to me that there are many cases where inheritance doesn't help much if the inherited parent data is not availaible to the children without accessor methods. It's not that you can't get the data (via methods) but standard LabVIEW clusters make access to the data so easy, that it's hard to see how the native object-oriented implementation will be worth the trouble of implementing it.

Link to comment

QUOTE(jdunham @ Sep 17 2007, 08:19 PM)

Hi Jan: Thanks for the tip. I will check out the Endevo toolkit. I have heard so much about it and I am glad to hear it could solve some problems. I think the by-reference objects will help with some other constructs I am working on. Does the toolkit also help with by-value classes?

The tool has the same features for by-value classes, GOOP 3 classes and the new lvclass based OpenG classes. Class templates, method templates, icon management, wire editor, and project class glyph, class renaming, changing inheritance.

Jan

Link to comment

QUOTE(jdunham @ Sep 17 2007, 01:19 PM)

However, I do still wonder whether NI will move toward access of protected data. It seems to me that there are many cases where inheritance doesn't help much if the inherited parent data is not availaible to the children without accessor methods. It's not that you can't get the data (via methods) but standard LabVIEW clusters make access to the data so easy, that it's hard to see how the native object-oriented implementation will be worth the trouble of implementing it.

Nope. No plans for protected data.

In LV8.2, we introduced private data. One of the major time sinks was creating get/set accessor VIs to the data. In LV8.5, we introduced the tools to accelerate this process.

In much the same way, I want to see us add tools to support protected access to data. Note, I said "protected access to data", not "protected data." Such tools would allow you to create a set of VIs on the outer class whose block diagram is simply "unbundle element and call the element's member VI". These generated wrappers could be public or protected. A user might use the tool to wrap a contained element's interface and then might choose to delete some of the created VIs so that not all operations are exported, resulting in a very precise set of available operations for callers.

Creating a language where you must go through functions to access data, and the only direct access to data is in a limited, known set of functions, is a very high priority for code correctness in a massively parallel programming language (aka LabVIEW). The integrated development environment for such a language (aka LabVIEW's editor) needs to support shortcuts for users to create the accessor functions. But time is far better spent on such tools than on cutting holes in the language syntax that result in ambiguous code execution.

I realize that the vast majority of programs are a single developer who isn't worried about someone else on the team corrupting the data. But even in the single developer case, LabVIEW, as a test and measurement language, ought to be able to *certify* the correctness of code. The ability to identify all access points to a piece of data is critical in that code correctness.

You can just provide get/set access to the data if you want -- get a contained object, call some methods on it, then set it back into the owning object. Those get/set VIs can be made protected scope. And, if you really want public or protected data with all its insides splayed out for the vultures of the world to dig into, use a cluster. A quick "get/set" accessor for the entire cluster will make it so that you can do arbitrary work on the data.

Link to comment

QUOTE(Aristos Queue @ Sep 18 2007, 11:12 AM)

Yes.

QUOTE(Aristos Queue @ Sep 18 2007, 11:12 AM)

...I realize that the vast majority of programs are a single developer who isn't worried about someone else on the team corrupting the data. But even in the single developer case, LabVIEW, as a test and measurement language, ought to be able to *certify* the correctness of code. The ability to identify all access points to a piece of data is critical in that code correctness.

Yes, yes and yes.

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.