Jump to content

Dynamic Dispatches for DVRs


Recommended Posts

So I've run into a use case where I can't think of a way out of my problem without having some sort of DVR-based inheritance mechanism. The problem being of course, that dynamic dispatches don't work with DVRs. Then it dawned on me I already have working code that does exactly what I need to do using a trick like so:

Class A defines a method which takes a Class A DVR Refnum in and out, and a Class A value which the dynamic dispatch is based off of. Like so:

post-11742-0-22054400-1289427693_thumb.p

The Type value is never actually operated on, it's only used to invoke the dynamic dispatch mechanism. Inheriting classes then implement the same interface, but are required to do some extra work before they can operate on data:

post-11742-0-89117800-1289427754_thumb.p

The situation that needs dealing with is the DVR terminal remains a Class A DVR refnum, so it must be explicitly cast to a Class B DVR refnum before it can be operated on in a Class B context.

As a courtesy, Class A also defines a helper method to invoke the dynamic methods:

post-11742-0-62794600-1289427881_thumb.p

Over all the implementation is definitely more messy, but as far as I can tell it works. Of course there are people here far more learned in the art of LabVIEW OOPs than I, so I figured I'd post to see if I'm missing something entirely obvious.

A few notes:

The helper method (third image, Class A: Initialize Object.vi) retrieves a default value for the class to avoid making possible copies of large data sets. Think arrays etc, only the static size of the default value (usually quite small) ever gets duplicated...

Casting the DVR does require a lock to be momentarily obtained on the refnum. Probably not important for most implementations, but I've been bitten by that in other parts of my code.

This pattern requires the class which defines the interface to implement two methods: one at the DVR level and one at the by-value level. Descendant classes only need to worry about the by-value method, but do require a bit of extra work. Strictly speaking, the DVR method isn't required in the base, but it makes using the class much easier due to the behavior of DVR refnums...

A BIG WARNING, is that this pattern breaks the atomic nature of the dynamic dispatch call chain. Take a careful look at the second screen shot, the parent implementation is called, after which anything can happen to the DVR before the Class B implementation gets a crack at operating on the data. This is exactly why I think I need the implementation to work this way, but could seriously break applications which require the entire call chain to be acted on atomically.

Code (LV2010) attached: DDDVRs.zip

Thoughts?

-m

Link to comment
So I've run into a use case where I can't think of a way out of my problem without having some sort of DVR-based inheritance mechanism. The problem being of course, that dynamic dispatches don't work with DVRs. Then it dawned on me I already have working code that does exactly what I need to do using a trick like so:

Are you not satisfied with calling dynamic dispatch inside the in-place structure? (you need to use the preserve runtime class vi after the dispatch.)

This seems like a significantly more complicated way to do that, and by your own admission destroys the one guarantee you need from the singleton pattern.

I can't see a reason to do this. Instantiating a default value of a class could be horrendous depending on how bad the datatype is.

~Jon

Link to comment

First, neat trick AQ! I'd have never thought of that, especially since the behavior of that loop is usually the exact opposite of what is needed. Don't know how many bugs I've tracked down to not having shifters on a for loop...

Are you not satisfied with calling dynamic dispatch inside the in-place structure?

A) I'm completely with Jon on this one. If you have a subVI that does all this work, why not just call the dynamic dispatch VI inside the inplace element structure?

Valid questions. Also note I said I *think* I need something like this. I still haven't wrapped my brain around how to get around my problem. I was still trying to distill the situation to its fundamentals and decided to try to "talk" this through. Thanks by the way for paying attention to this wingnut idea, I realize how stupid it looks (and consequently how foolish I likely appear).

The lock on the refnum which is required to invoke the dynamic dispatch (since it must operate on a value not a refnum) is causing me issues due to some circular references. The original post above allows me to decouple the lock needed to invoke the parent implementations from that of a given class implementation.

ObjectA contains a reference to ObjectB, and vice versa.

The ObjectA refnum is locked to invoke a dynamic dispatch method.

The method locks the ObjectB refnum so it can operate on ObjectB.

ObjectB can no longer operate on ObjectA...

What I've come to realize during the last few hours is that I went about this entirely wrong. What I really ought to be doing is changing the order of operations such that ObjectB does not need to operate on ObjectA.

Link to comment

What I've come to realize during the last few hours is that I went about this entirely wrong. What I really ought to be doing is changing the order of operations such that ObjectB does not need to operate on ObjectA.

You might also consider a model where a single DVR refers to a cluster of the two objects or a third class has an instance of the other two classes as members and you use a single reference to that third class.

First, neat trick AQ! I'd have never thought of that, especially since the behavior of that loop is usually the exact opposite of what is needed. Don't know how many bugs I've tracked down to not having shifters on a for loop...

For the record, you could just fork the wire, but that creates a copy of your object -- potentially expensive. The zero-iteration for loop uses the type of your object and constructs a default object -- which, on desktop targets, is essentially free since we have only one instance of the default object that gets shared around. Because the original class wire isn't modified on either branch, LV doesn't create a copy of the original object.

There's another way to get this that might be considered less of a hack -- use the Preserve Runtime Class primitive. Fork your class wire into the center terminal of that primitive and wire a LabVIEW Object constant to the left input. Ignore the error out because there will always be an error doing this, but the output is a default instance of the class of the object on the center terminal.

  • Like 1
Link to comment
  • 2 months later...

I wanted to test the for loop trick with N=0 for getting a default value of a LabVIEW class instances. I tested with LV 2010 on OS X. It doesn't seem to work at all. See the attached picture and project for LV 2010.

In the top wire I would expect the wire to have a default instance of the Parent class but it has a LabVIEW Object. The second wire has Child class instance default value as expected. The third and fourth wire have Parent class default value when I was expecting Child class default value for both wires.

Did I understand something incorrectly?

post-4014-0-90494800-1296332211_thumb.pn

Default Value Propagation Fail.zip

Link to comment

No, you didn't misunderstand anything. 2010 is broken. Of course, the CAR didn't get discovered until the day *after* 2010 SP1 was already finalized for release.

WORKAROUND: Change the constants going into the For Loop into controls. (The ones wired to the type cast primitives are fine to leave as constants.)

I'm really embarrassed by this bug. I'm reviewing our test coverage because this was a fully tested case, I thought. Clearly something isn't right in the test suite for this to have shipped. It WILL be fixed in 2011. Along with a whole lot of other issues. 2010 is really starting to piss me off as a release... it really appears to be a more stable release than its predecessors, with fewer CARs affecting fewer customers. But the few CARs that are in there... wow. It's like some elf went through the code and decided to just move all the entropy bits into one pile so they'd be really easy to spot when we're doing cleanup for 2011.

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.