jgcode Posted March 6, 2009 Report Share Posted March 6, 2009 I have a Jet class that inherits from Airplane class. Both methods have a setSpeed vi which are different. In another Jet method accelerate I am trying to call the parent Airplane setSpeed method. When I wire the Jet object into the Airplane setSpeed method it dynamically changes to the Jet setSpeed method (understandable). I thought using the To More Specific/Generic Class nodes would stop this behavior? But even though in edit time the Airplane setSpeed VI is shown (as per the picture) it runs the Jet setSpeed at runtime (verified by debugging). Obviously if it was the same method (override) I could use the Call Parent Method node inside the VI but its not this case. Is there a way to call a parent-method-VI in a different child method, when the child has an override method for that parent-method-VI? I am trying to implement some JAVA code in LabVIEW - so JAVA can do it. Regards JG I am coding in LV8.6.1 Quote Link to comment
Yair Posted March 6, 2009 Report Share Posted March 6, 2009 I'm not sure if you can have VIs in inherited classes which have the same name and are not override VIs. Try reading this. That said, I'm far from an expert on LVOOP. This smells like a bug from your description. Quote Link to comment
mje Posted March 6, 2009 Report Share Posted March 6, 2009 Right, the behavior you're seeing is by design, it's fundamental to dynamic dispatches (or polymorphism, as it's usually called in object oriented design), it has to be that way to be following the object paradigm. Text-based languages handle this dilemma by allowing you to qualify the method name in some way (Parent::SetSpeed, or AirPlane::SetSpeed). I'm aware of no such mechanism in LabVIEW, nor can I think of any hack to get it done in LabVIEW. Quote Link to comment
Aristos Queue Posted March 6, 2009 Report Share Posted March 6, 2009 No, you cannot do what you are seeking to do. It is impossible, by design, and if you find a way to do it, please let me know so we can fix it. Now, having said that... What you claim you are trying to do is this: The parent defines functionality X. The child overrides functionality X. You want to have a child object call Parent:X. But you would never really want to do this. Doing so completely violates the definition of child -- child overrode the behavior of X for some reason, which may be because the parent behavior is invalid or doesn't do sufficent input checking, or doesn't keep related fields up-to-date... etc. What you actually want to do is this: The parent defines functionality X. The parent defines functionality Y, which happens to be identical to X. (So it is probably implemented as Y calls X in the parent, but that's private implementation detail, so we don't know... the parent could have duplicated the VI, or call into a common subVI...) The child overrides functionality Y. You have a child object call functionality X. In this case, the parent has exposed both the wrapper layer and the core layer -- and exposed it as two separate methods even though itself doesn't need to have any difference between these. That's how you'll handle the JAVA code. Quote Link to comment
jgcode Posted March 6, 2009 Author Report Share Posted March 6, 2009 QUOTE (Aristos Queue @ Mar 6 2009, 05:59 AM) No, you cannot do what you are seeking to do. It is impossible, by design, and if you find a way to do it, please let me know so we can fix it. Thanks everyone. I can't comment on the OOA&D aspect of the code as this was just an example. And I have never had the need to do this in the past. Therefore, even though it is possible to do this in JAVA - are you saying that you would never do this in the real world? Is it just that the example sucks? Quote Link to comment
Aristos Queue Posted March 6, 2009 Report Share Posted March 6, 2009 QUOTE (jgcode @ Mar 5 2009, 04:44 PM) Therefore, even though it is possible to do this in JAVA - are you saying that you would never do this in the real world? I am saying that I would never do this in the real world and I would strongly advise anyone else against ever doing it. It opens the door to your child object (and all of its descendants) being in an inconsistent state that their designers may never have handled. It can be used to hack around a poorly designed parent class. The one case I am most familiar with, making a direct call to grandparent functionality (bypassing the parent) did let a software team ship a product on time, but that hack bit them badly in the next release when they didn't go back to refactor the code because a new descendant class was added that assumed (rightfully) that the functionality of the parent (which was being bypassed) would be invoked.Essentially, the situation was this Grandparent Parent Child Each level of the hierarchy had an implementation of RegisterMe(). Parent's version registered the object with a framework. Child had its own overriding implementation of RegisterMe() did some checking of itself and if certain flags were set, the function would return an error; if those flags were not set, the function would call up to the Parent implementation to do the registration. There was one place in the code where the correct behavior was to do the registration of a Child object even though the flags were set on Child that would normally make the function return an error. Refactoring the code at that point was hard -- they would have had to change some interfaces that had been stabilized. So the programmers called directly up to Parent's version, bypassing the flag check. By just bypassing Parent, the team made Child work correctly. Fine -- they shipped. Next version, a new Grandchild class was introduced. Grandchild overrode RegisterMe() such that it called up to Child's implementation. If Child returned an error, so did Grandchild. But if Child did not return an error, Grandchild did some more work, including registering itself with a second framework. Grandchild assumed that anytime it was registered with the first framework, it would also be registered with the second framework. It assumed that the code protected it from ever getting into an inconsistent state. The problem was that a Grandchild object got passed to that special section of code that called directly to Parent:RegisterMe(). That registered Grandchild with the first framework but not the second. Grandchild's desgin predicate was violated. No one noticed this bug until after release of the new version... the first to notice was a customer. Serious bug... required a custom patch for the customer. Expensive. Object-oriented design is supposed to prevent design errors like that. The whole point is that there are predicates that each class defines: I am in state X. I define a set of functions that let me transition from state X to state X+1. I have no functions that ever let me reach state X+2 without going through state X+1. I have no functions that put me in state Y EVER. Therefore I don't have to check for state Y, and I can assume that things done in state X+1 are taken care of when I am in X+2." With these predicates, the software developer can actually make logical arguments about the correctness of his/her code. This shield is one that I took great pains to maintain in the design of LabVIEW classes. We eliminated many of the aspects of other OO languages that keep you from asserting certain truths. You cannot have two VIs of the same name that do not override each other by having different connector panes. You cannot directly call an ancestor implementation of a method You cannot as a user directly edit the private data of a class through any UI mechanism [Yes, I know this causes a problem for debugging and we're still working on that problem, but don't expect anything soon. But while it is a problem when debugging, for a running app this is a feature.] You cannot have public or protected data [This one we could relax and it would be your choice when to have public data about which you could make zero assertions of correctness, but the reasons for all private data are explained in the LabVOOP white paper.] I feel this makes LabVIEW a more robust language, something that is important in all the industrial control and hardware feedback situations that LabVIEW is used for. Quote Link to comment
jgcode Posted March 6, 2009 Author Report Share Posted March 6, 2009 QUOTE (Aristos Queue @ Mar 6 2009, 09:12 AM) I feel this makes LabVIEW a more robust language, something that is important in all the industrial control and hardware feedback situations that LabVIEW is used for. Thanks for the great reply AQ. You are a great resource to these forums and your time is much appreciated. :beer: Quote Link to comment
jgcode Posted March 7, 2009 Author Report Share Posted March 7, 2009 Dynamically loading class plugins would be also affected as well when override methods are used to extend the behaviour of the top level class. So I can definitely understand that this would behavior is not recommended and why it has been implemented this way. Thanks! Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.