05-30-2013 03:51 PM
Given two classes with dynamic dispatch VIs (LV 2011)
Parent
+ m1:string
Child
+ m1:string
+ p1:string
Where Child inherits from Parent.
How do I get Child.p1 (image below) to return the results of Parent.m1? I.e., Child.p1 needs to directly call Parent.m1, and _not_ Child.m1.
I've tried what would seem intutive, but it does not do what I expect, even though it looks like it should as it claims it will execute the Parent.m1 VI:
Attached is a zip of the test case.
Thanks!
05-30-2013 04:49 PM
The reason your code doesn't work is that the decision which VI to execute is always made at run-time based on the actual object in the wire, not based on the wire type itself. Your upcast simply changes the edit-time type of the wire, but the object is still a child.
The more general solution is that you can't and shouldn't - deciding how to do the "m1" operation should be up to m1 and not anyone else. That means that you should call the m1 of the class that's on the wire. Now, if child.m1 wants to call the parent implementation, it can use the call parent implementation node and case out its own code.
05-31-2013 12:38 AM - edited 05-31-2013 12:53 AM
I assume you are using dynamic dispatch vi's
Here is a workaround that I have employed
I use the call parent method in the cluster class variant Palette
If you are not using dynamic dispatch, Just wire the parent method directly in, this is not a real problem.
#Edit, The False case panel should have been an unbundle element or a method other than the calling one.
05-31-2013 09:17 AM
The CallParent method calls the parent of the VI that is being overridden. However, I need the Child (e.g., Child.p1) to call another method in Parent (e.g., Parent.m1) which has a been overridden in Child (e.g., Child.m1) without dispatching to Child.m1.
05-31-2013 09:39 AM
I agree. The problem I am solving needs a specialization of Parent.m1 (without modifying Parent) that puts additional constraints on the services of m1.
In other languages (e.g. Java), I would implement a new Child.m1(N) that overloads Parent.m1() but still calls Parent.m1() to get the services of Parent.m1() (e.g., by calling super()).
Unfortunately LV does not support overloading.
What I am looking for is a workaround to this limitation. My first attempt was to implement Child.p1(N) and have it call Parent.m1(), but that didn't work.
05-31-2013 10:36 AM
If you don't want to change the API of m1, what you can do is this - add a boolean field to the child class which indicates you want to call the parent. Set that field in child.p1, then call m1, then reset it. Inside child.m1, if the field has been set, then you case out the code and call the parent implementation as shown. Note that if add additional grandchildren which implement m1, they will have to be aware of this behavior if you want them to behave similarly.
05-31-2013 11:28 AM
True, however there is a race condition.
Consider two clients - clientA and clientB - both running in parallel: clientA calls instance.p1 and clientB calls instance.m1. The race condition occurs when instance.p1 (clientA's thread) sets the callParent flag, then clientB's thread calls instance.m1, then clientA's thread calls instance.m1.
05-31-2013 04:39 PM
@mflegel wrote:
True, however there is a race condition.
Consider two clients - clientA and clientB - both running in parallel: clientA calls instance.p1 and clientB calls instance.m1. The race condition occurs when instance.p1 (clientA's thread) sets the callParent flag, then clientB's thread calls instance.m1, then clientA's thread calls instance.m1.
This doesn't make any sense (to me, at least). The flag is part of the instance's data, there's no way there would be interference between the two instances. One instance can't write to the other's data.
Can you simply modify Parent so that it has a non-dynamic-dispatch method that actually does the work of m1? Then you can call that from Parent.m1, or call it directly to achieve the behavior you want here.
05-31-2013 05:08 PM
The flag is part of the instance data, but there can be interference when the two clients call into the same instance at the same time in their own threads of execution (maybe even running on different cores).
Modification of the Parent is not an option.
There's a few constraints I forgot to mention:
To meet these constraints:
06-01-2013 12:59 PM
If your instances are shared through DVRs, then a single instance can't be accessed at the same time (assuming the object itself is what's in the DVR and not references inside the object) - the DVR mechanism protects you from that and once you use the IPE structure to access a DVR, any other structure which wants it will have to wait until the first structure is done with it before it can proceed. Thus, setting and unsetting the flag inside the IPES should not cause race conditions.
Likewise, if you simply split the class wire you created two separate instances and again there is no race condition (although that doesn't seem to be correct behavior in your case).
Note that it might be possible to open an explicit VI server reference to parent.m1 and run it with the CBR node, but I have a vague recollection that if you do that LV will still use the DD mechaism to run child.m1. This will probably not happen if you use the Set Ctl Val and Run VI methods, but that workaround is so bad it hurts me just to type it.