Jump to content
shoneill

Inheritance versus Composition

Recommended Posts

So this is meant as a continuation of a discussion of relative merits of inheritance versus composition between myself and Shaun R to be found HERE.

Share this post


Link to post
Share on other sites

It is? Wow. News to me :D

 

Perhaps a moderator can move each of our last two posts here?

Share this post


Link to post
Share on other sites

Nobody moved the relevent posts across, so I'll have to cut and paste bits here instead instead of quote the originals.
 
 
Hmm. Composition Vs Inheritance. I'm half tempted to show you an example without classes at all just to show that using lists has nothing to do with inheritance. As for composition. I though you were proffering the Composite Pattern. When you talk of composition, I think of [object] composition like the image below which is a form of inheritance IMO :wacko:
 
post-15232-0-06627700-1432178606_thumb.p
 
We are already foundering on terminology so it is no wonder people have a tough time with OOP. :P
 

I don't want to weigh this relatively focussed topic down with previous discussions which may or may not be applicable and to which I was not a party.  I also don't mean to be nasty but your usage of both has no relevance to the discussion.

Nothing to do with discussion. It is the name of a criticism of OOP that what methods and properties that an object should consist of, is subjective and based on the viewpoint of the programmer. If you haven't had or seen that argument; I would be very surprised.The relevance is implicit. The Composite pattern yields a "Bottom up design". The Lists are a "Top Down design" these are supersets to design patterns in any paradigm. You are looking at the system and saying "what pattern can I apply"?. I am looking at just the test management and whats the best way to solve this bit. (oh how I wish we could inherit from  TreeView)
 

The obvious drawback of your idea is the static linkage to the List class.  While the List class is most likely a lovely piece of work, if you want to implement a Frame as a different kind of grouping (don't ask me, I'm just theorizing, perhaps a conditional looping of individual elements until a condition is met) then either you build that into your List class or you implement it separately in your child class.  By moving the List functionality into the child class, each child is free to implement whatever method of aggregation they see fit without requiring interface bloat.  Each item implements whatever it needs.  You could have several different flavours of collections (lists) which do things different based on some corner cases.

So this is a "what if" scenario that doesn't really pose an issue for lists, but is the type of thing the pattern was designed for. I'm not even sure I understand "interface bloat" in terms of a LabVIEW implementation since I either use the TList Vis or use the "Frame" VIs which at this pint probably only has one or two VIs (Get Result and Execute?). Each child is also free to handle its own "aggregation" however it sees fit. You can also have "several different flavours of collections (lists)" as well as Steps, Actions and any other classes you care to include but the main thing we want to do is move them around within the list, change their order and add and remove them so it;s hardly bloat if we are actually using those functions.
 

So imagine a "collection" which internally manages a List (your class). When dealing with a collection (strictly typed child of Frame), you have the exposed methods for the list, when working with Frames (when you don't need to know whether it's a list or not) you have a much cleaner interface. By moving your same List class up two levels of the hierarchy you gain a lot of flexibility and remove static linkage to the functionality of your list. What are the downsides you see with this approach? The only downside I see is the creation of some proxy VIs which, depending on your taste might be enough to sway you


I consider a collection to be the same as a list, so your first sentence doesn't make a lot of sense. But no. In LabVIEW you don't have the exposed methods unless you override explicitly so I'm not going to create a VI in the child for every VI in the base jsut to give me the right coloured squares. I will just use the base class VIs. Granted in C#, Delphi et.al your code completion list will be shorter so you can reduce "interface bloat", but they get those automatically without writing skeleton functions. We don't have that in LabVIEW so interface bloat is moot as far as I'm concerned.

 

The downsides I see is that it really doesn't give you much and it kind of fixes you into an application architecture that may not be that good for other aspects. For Sequences and Steps (slipped back into TS terminology as we don;t really know what a Frame is) they are just line items in a list. It is "actions" that actually do stuff and everything else is just ordering the actions. All you really need is a list and execute to manage sequences, steps and actions. What you actually execute is a different matter.

Edited by ShaunR

Share this post


Link to post
Share on other sites
Nobody moved the relevent posts across, so I'll have to cut and paste bits here instead instead of quote the originals.

 

Hmm. Composition Vs Inheritance. I'm half tempted to show you an example without classes at all just to show that using lists has nothing to do with inheritance. As for composition. I though you were proffering the Composite Pattern. When you talk of composition, I think of [object] composition like the image below which is a form of inheritance IMO :wacko:

 

 

I am and I am.  I am referring to both the composite pattern AND composition, both terms being used correctly.  The idea of a Frame containing a List class internally and handling this WITHIN the borders of it's encapsulation : not exposed) is composition in the classical sense, one class containing another in order to implement some aspect of the functionality in a sub-class.  The fact that this Frame incorporating a List (which accepts Frames as items) is also a Frame object is the Composite Pattern.  The item representing multiple instances of a defined object type is transparently exchangeable with an item representing a single instance of the same object type.

 

As to your image.  Hmm, I see no evidence of composition here at all.  There's only a single object wire, no observable sub-objects.  I think you're simply showing inheritance at work here which is most definitely NOT composition (in the generally accepted sense).  If you're defining some super-literal definition of composition then you need to make that clear but the standard definition of composition is that a class "car" can have  four "wheels".  If each "wheel" is itself an object (different inheritance hierarchy than "car") then by giving an object "car" four member classes of type "wheel" allows the actual implementation of "wheel" to vary independently of "car" and also allows run-time substitution, something which Inheritance cannot.  It would theoretically be possible to replace four standard "wheels" with jet propulsion units without having to modify "car" at all.  Only the Interface for "wheel" needs to be compatibly with the implemented functionality.

 

In your case, "Truck" IS A "Vehicle".  This is Inheritance.  In my example "car" HAS "wheel"s, this is composition.  It's identity versus possession.  Two very different approaches to essentially different problems.

 

Nothing to do with discussion

 

 

Good, then let's move on.

 

So this is a "what if" scenario that doesn't really pose an issue for lists, but is the type of thing the pattern was designed for. I'm not even sure I understand "interface bloat" in terms of a LabVIEW implementation since I either use the TList Vis or use the "Frame" VIs which at this pint probably only has one or two VIs (Get Result and Execute?). Each child is also free to handle its own "aggregation" however it sees fit. You can also have "several different flavours of collections (lists)" as well as Steps, Actions and any other classes you care to include but the main thing we want to do is move them around within the list, change their order and add and remove them so it;s hardly bloat if we are actually using those functions.

 

 

Well I think a "What if" scenario when the problem has been defined as variable, i.e. not knowing which requirements are going to come next as was expressed in the original post, is an important thing to consider.

 

The aspect of Interface bloat is easy to understand.  If I take one of your Frame objects I can call each and every public method of your List class on my Frame.  Even if they're not required.  Even if they're not on the Menu but they are there and any tool which auto-populates a menu to show accessible functions will be bloated.  The methods are there and supported.  I'm referring to the actual Class interface, not whatever is shown to (or hidden from) the user.

 

Another topic: So which object type does your List contain?  Some generic datatype?  So I could feasibly call Frame.Add Item and pass it an Action and similarly call Action.Add Item and pass it a Frame?  Or do you have some way of hiding these methods of your List after inheritance?  The only thing I can think of is "Community" scope but IIRC this is bugged to hell.

 

I consider a collection to be the same as a list, so your first sentence doesn't make a lot of sense. But no. In LabVIEW you don't have the exposed methods unless you override explicitly so I'm not going to create a VI in the child for every VI in the base jsut to give me the right coloured squares. I will just use the base class VIs. Granted in C#, Delphi et.al your code completion list will be shorter so you can reduce "interface bloat", but they get those automatically without writing skeleton functions. We don't have that in LabVIEW so interface bloat is moot as far as I'm concerned.

 

 

The bolded term is simply wrong.  Flat out, no discussion.  I can call ANY public methods you have defined for your List on any Frame object.  It will call the Parent implementation (I think this is what you're getting at) but I can do this, it's legal and there's nothing to stop me doing it.  Depending on how you present your VIs to the end-user you may have any subset of the interface listed there, but doing so does NOT remove them from the interface.  The methods are there, they can be called and they do something.  You even say later that "I will just use the base class VIs.".  Exactly.  But why have those methods available when they're not always needed?  That's interface bloat right there.  Parent methods are just as much a part of an object's interface as it's own.  This is because the child IS A parent (inheritance).  Making a shorter list, looking only at that level of the inheritance hierarchy or just plain pretending the methods do not exist for that object does not mean that the methods are not there.

 

So for Frames which are only a single item and will only ever BE a single item, the List methods are bloat.  Taking things further, if (beyond Frame initialisation) you never need to deal directly with the List functionality, having them there is bloat, exposed methods which at best confuse and at worst destroy any encapsulated functionality you might have implemented.  What if I choose to Add a new item to a List half way through execution so that the currently executed step is suddenly a different one?  Why have methods available which are unneccessary?

 

 

The downsides I see is that it really doesn't give you much and it kind of fixes you into an application architecture that may not be that good for other aspects. For Sequences and Steps (slipped back into TS terminology as we don;t really know what a Frame is) they are just line items in a list. It is "actions" that actually do stuff and everything else is just ordering the actions. All you really need is a list and execute to manage sequences, steps and actions. What you actually execute is a different matter.

 

Here we have things backwards.

 

Inheritance (inheriting from List) fixes us into the fact that each and every Frame is a List for ever and ever, immutable.

 

Using Composition, those Frames which need to be a List can manage their list privately, knowing what to do when told to execute.  If one wants to have a Collection, one wants to have a State machine, one wants to have a Client-Server connection, if one wants to pick random items from disk or whatever then each and every Frame is free to implement the grouping methodology it requires and handle it appropriately when told to execute.  That fixes you into nothing.  It frees you to do whatever you need whenever you need.  You can access the EXACT same functionality as with Inheritance but the List methods will NOT be callable on Frame.  When a Frame with an internal List is told to execute, it will call the appropriate methods on it's List without the caller needing to know or see any of it.  THIS is the composite pattern combined with composition.  Allowing you to treat a List of Frames as a Frame as the same type of object is the composite pattern.  Using an internal List to give extra functionality and choosing which methods (if any) are exposed is composition.  By doing so you also expose "Add" functions which accept ONLY Frames which prevents a cross-communication with other object types, something which the normal "List" methods cannot do.

 

Shane

Share this post


Link to post
Share on other sites

Hmm, you sound like my wife when she's fed up with a discussion and just can't be bothered any more. :unsure:

  • Like 2

Share this post


Link to post
Share on other sites

By the way, I recently came across several discussions on the best way to implement the "Composite pattern".

 

  1. Some claim that the interface for adding, removing and listing sub-objects (Interface, not the actual code - this still leaves the concrete implementation the freedom to implement whichever method of grouping they require) should be part of the base object type.
    This still feels like interface bloat to me.  I am forcing a single object (say, a Circle) to implement methods like "Add Child" or "Remove Child" even though those methods make no sense for that object.  You can't add anything to a Circle without violating it's identity as a circle.
  2. Others claim that two differing interfaces are required, one with and one without the extra methods.
    The addition of a "Is composite?" option allows the user to then determine whether the object is comprised of sub-objects or not (or whether it's even capable, even if it currently is not).  A static cast could then be made to allow access to the extra methods if really required.

I tend to think sometimes, within certain application spaces, that a sequence of test routines (for example) are not simply a collection but the ordering is important and more often than not, leaving out a single step will negate the benefit of the entire sequence.  Can this be aligned with the composite pattern? Is there a different name for this?  It's like using the composite pattern during object creation but not beyond that.  A Sequence can be created using single steps or other sequences which in turn can comprise of single steps or other sequences which in turn......  This seems to obey the ideas of the somposite pattern but the ability to access/modify or delete sub-objects afterwards can be quite detrimental in these situations.

 

Has anyone else got an opinion on this?

Edited by shoneill

Share this post


Link to post
Share on other sites

On a slightly different note:

 

In the original discussion leading up to this side thread the ball was brought to roll by the mention of "If you derive Sequence and Step from a List object.".  This involves inheritance, with the derived class referring to the class which has inherited from some base class.

 

But later (in this thread) it has just occurred to me that the following text "show you an example without classes at all just to show that using lists has nothing to do with inheritance" seems to contradict that.

 

Perhaps we have our lines crossed?  Perhaps you meant to refer to object composition in your original "derive" comment?  In this case we're actually talking about the same thing.  The entirety of the "Inheritance vs Composition" bases around the typical interpretation of the term "derived class" which is pretty well established to involve inheritance.  If it was not meant in that sense, then the entire discussion is moot.  this would also explain your surprise at the discussion even being about composition vs inheritance at all.

Share this post


Link to post
Share on other sites

If it was not meant in that sense, then the entire discussion is moot.  this would also explain your surprise at the discussion even being about composition vs inheritance at all.

I gave you closure; move on. The List is here by the way.

Share this post


Link to post
Share on other sites

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.


  • Similar Content

    • By Ryan Vallieu
      I have seemingly found an issue with the shipping example code for Nested Malleable VIs.  Another user has verified that he saw the same behavior in 2019.
       
      I am working through the examples and the presentation from NIWeek 2019.  In running the Lesson 2b code (C:\Program Files (x86)\National Instruments\LabVIEW 2019\examples\Malleable VIs\Nested Malleable VIs) I found the Equals.vi in the class was not being leveraged and the search failed.  When I went to my LabVIEW 2018 machine and ran the Lesson 2b.vi the code worked to find the element by correctly leveraging the in-class Equals.vi.
      One difference I see is that in the 2018 example the Equal.vi is in the example folder with the code, and in 2019 the Equal.vi has been moved to VI.lib - otherwise the code looks to be the same.  The Equals.vi code looks identical, and the calling VIM look identical.  I posted on the LabVIEW NI.com forum here: 
      https://forums.ni.com/t5/LabVIEW/LabVIEW-2019-Malleable-VIs-Shipping-Examples-Lesson-2b-Nested/m-p/3966044/highlight/false#M1129678
       
      I am trying to determine what may have broken or changed between the implementation in 2018 and 2019, visually the code looks the same.
    • By Voklaif
      Hello all,
      I am programming with LabVIEW for around 2 years and was recently stumbled upon LVOOP.
      I am required to write a communication protocol to work with a micro-controller, which later will be also used for ATP and debug purposes.
      I want to build the program "correctly" from the beginning so it will be maintainable and flexible to additions and changes.
      My natural way of building a program would have been a queued state machine, with several loops, each loop is in charge of a different module (one for GUI obviously), but as I stated in the beginning, I want to use LVOOP.
      Does anyone have a LVOOP project I can use as reference? I've searched online and found some nice examples, but they are small and teach you the basic stuff.
      For me it's important to see the how to use the project tree wisely, where to place the classes, see the managing loop and to learn as much as possible before I create one of my own.
      Thanks in advance,
      Voklaif
    • By GregFreeman
      I have an array of classes, let's call the object TestPass, of size 1 (but it is an array because it can scale out to multiple test passes). In this class, there is one other nested class which is not too complex, then various numeric and string fields to hold some private data. There is also an array of clusters. In this cluster there is a string, two XY pair clusters, and an integer. Not very confusing.
      This array of clusters gets fairly large, however, upwards of 80-100k elements. What I am finding is when I index the array of pass classes it is crazy slow. On the order of 30 ms. Doesn't seem like much, but we are indexing the array in our method to "Get Current Pass" which is used in various places throughout our code. This is adding potentially hours to our test time over the 80k devices we are testing. 
      So, I started digging. When I flatten the class to a string and get the length, it's 3 mb. But, when I run the function with the profiler is is allocating close to 20 mb of memory!
      My gut feel was that the string is causing the issues. So I removed the string from the cluster and the index time went to 0 ms. 
      Luckily we can normalize a bit and pull the strings out of the cluster since a lot of them are duplicates. But it makes our data model a bit uglier. 
      Has anyone seen these kind of performance issues before? I saw them in 2013 and 2017.
    • By ted Francis
      I am new to LVOOP and have jsut started writing my first LVOOP program which I have attached.
      I would appreciate greatly help with the question I have
      Thank you in advance 
      Ted
      This vi will perform two tasks 
      1.Generating Report data sheet for metrology 
      2. updating the scales in a MAX .nce file
      1. Metrology will input calibration information into the tables on the tabs
      Metrology will then click "Update Tables" then "Create Report ( create report section of code is not yet written
      Update Tables will write all information entered in the tabs to class varaibles and will also delete current Max informatiomn
      2. Metrology will click "Load NCE Scale"
      vi will prompt for nce file to load and then once file is selected, display existing scales for two channels (Current Motor 1 and 
      Current Motor 2)
      Metrology will then click "Update Scales"  the program will replace the existing scales with those entered in Step 5.14 and 5.15
      from the tables on the tab
      Question 1.  Steps 5.14 and 5.15 are needed by both classes ( Table Variable and MAX) - what is the best way to share this information
       
      CAT0000032 Class Version.zip
    • By shoneill
      I was browing through the actor framework discussions on the NI site yesterday and I came across a statement by AQ.
      Never inherit a concrete class from another concrete class
      I had to think about that for a second.  The more I think about it, the more I realise that all of the LVOOP software I have been writing more or less adheres to this idea.  But I had never seen it stated so succinctly before.  Now that may just be down to me being a bit slow and all, but in the muddy and murky world of "correct" in OOP-land, this seems to be a pretty good rult to hold on to.
      Are there others which can help wannabe plebs like me grasp the correct notions a bit better?  How about only ever calling concrete methods from within the owning class, never from without?  I'm learning for a long time now, but somehow, my expectations of LVOOP and the reality always seem a little disconnected.  AQs statement above helped crystallise out some things which, up to that point, had been a bit nebulous in my mind.  Well, I say I'm learning..... I'm certainly using my brain to investigate the subject, whether or not I'm actually LEARNING is a matter for discussion... The older I get, the less sure I am that I've actually properly grasped something.  The old grey cells just seem to get more sceptical with time.  Maybe that in itself is learning...
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.