05-10-2017 10:53 AM
Not a DVR expert here, but maybe this helps (if in fact it's actually correct):
We *want* to think that creating a DVR is analagous to assigning a reference in C . But it isn't. Not quite. It's like you said -- a new instantiation of a typed dataspace. In the course of instantiation, it also gets initialized to the value we wire in.
The fact that you can make a DVR by wiring in a constant helps support this interpretation. The resulting DVR can be dereferenced and altered without ever affecting the constant.
Thus, I'd say that the "Help" is kinda misleading in its wording.
-Kevin P
05-10-2017 10:59 AM - edited 05-10-2017 11:00 AM
@CoastalMaineBird wrote:
So, how do i manage this? Does that mean that EVERYTHING that operates on that class has to use the DVR?
I'm pretty sure that's a yes. If you need to share access to a particular object, the original object wire should simply terminate at the "New DVR" node. That helps makes it clear that the DVR will now be the only way to have access to the object.
-Kevin P
05-10-2017 11:05 AM
@CoastalMaineBird wrote:
OK, the light bulb is turning on.
...
I see it now.
I knew you'd get it, but I didn't know what spew of alphabet soup would be needed to help you understand. It is quite a foreign concept in LabVIEW, and a concept that isn't easily grasped in texted based languages. Don't feel bad, many people misunderstand how DVRs are supposed to work. I know some were thinking they were linked somehow to a control on the front panel, and that writing to the DVR should change the value on the control, but it clearly doesn't work that way either.
As for the working with them in classes. I'm not sure how other people work with them, but what I tend to do is have a DVR in my class data, that is created on initialization. I can have other data in the class as well that isn't referenced based, but you need to be aware that this data won't be shared with parallel processes. If I have something that only gets set on initialize and from then on is read-only, then I might not put it in the DVR, inside the class. So then what is passed around is still just the class, and it goes into the sub functions, but there I have an in place that pulls out the data or writes to it. The DVR is created once in the initialize, and destroyed once in the close, and all functions are now using this class primarily as a by reference, with the few exceptions like the read-only by value things from initialize. The DVR at this point is going to be a type def'ed cluster to make changes to it easier.
Unofficial Forum Rules and Guidelines
Get going with G! - LabVIEW Wiki.
17 Part Blog on Automotive CAN bus. - Hooovahh - LabVIEW Overlord
05-10-2017 12:09 PM
@Hooovahh wrote:
what I tend to do is have a DVR in my class data, that is created on initialization.
When I tried that, I was not able to. I tried to put a DVR refnum inside the class private data, but the complaint was that it was a recursive definition (it contains a reference to itself, which can never resolve).
Do you put in some generic DVR and then typecast it, or did I do something else wrong?
Blog for (mostly LabVIEW) programmers: Tips And Tricks
05-10-2017 12:36 PM - edited 05-10-2017 12:37 PM
Don't put the class in the DVR, have the DVR only contain the data you want to be by reference, which in this case would be a scalar numeric. So make a cluster with a scalar numeric in it, type def it, create a DVR with it, create a constant of that DVR, place that constant in your class data (likely in a cluster). Now if you want to update the data available by reference you just update the typed cluster you made earlier and everything gets updated. I don't have access to a machine right now to post an example, but I think my CAN Frame Signal Conversion library uses this technique. Version 6 is the oldest and can be opened with 2011.
Unofficial Forum Rules and Guidelines
Get going with G! - LabVIEW Wiki.
17 Part Blog on Automotive CAN bus. - Hooovahh - LabVIEW Overlord
05-10-2017 12:37 PM - edited 05-10-2017 12:42 PM
It is quite a foreign concept in LabVIEW,
Well, the trouble is that I didn't connect the idea of SPLITTING the WIRE with MAKING A COPY.
I mean, I knew that's what happens, but I never really needed to care before now.
What I want is a "flow-thru" type of connection where you connect ANYTHING at the top left, and have an ANYTHING output at the top right, and a DVR output somewhere else.
That would let you make a DVR to THAT PARTICULAR WIRE.
Ain't no such beast, though.
Blog for (mostly LabVIEW) programmers: Tips And Tricks
05-10-2017 12:41 PM
@Hooovahh wrote:
Don't put the class in the DVR, have the DVR only contain the data you want to be by reference, which in this case would be a scalar numeric.
In this little demo case, that's true, but I want to have a reference to a particular instance of a CLASS, so that I can dereference it and call a method on it.
The child in this project does exactly that, and that part works fine, if I get the references straightened out.
Blog for (mostly LabVIEW) programmers: Tips And Tricks
05-10-2017 01:50 PM - edited 05-10-2017 01:55 PM
I speculated that this would NOT work, and indeed it doesn't, for the same reasons.
I made a class method to examine a U32 field, and if it's zero, create the DVR and stash it. If not, then pull out the U32 and typecast it.
It gets around the compiler self-referential recursion problem, and it refers to a single instance, but the DVR refers to a different copy of the data than the one it's derived from.
If you think of data flow vs. time, then at T1 in the diagram, there is ONE instance of the class, at T2 there is ONE instance of the class, but at T3 there are TWO instances of the class. The reference is to that extra copy made, and the main line is completely separate.
Blog for (mostly LabVIEW) programmers: Tips And Tricks
05-10-2017 02:45 PM - edited 05-10-2017 02:46 PM
Curious and interested. My own mental model and educated guesswork would predict that at T3 there's still only 1 object. This is based on predicting a smart enough compiler to see that one wire branch terminates without modifying the data on that wire. Very similar to what I'd expect if you replaced the "New DVR" node with an "Unbundle by Name" node (as is common practice in accessor functions).
I think that the "New DVR" node itself creates the new object dataspace, initialized to be equal to the value wired in. So the 2nd instance of the class doesn't come into existence until "New DVR" executes.
Comments from those in the know? Looking to learn here...
-Kevin P
05-10-2017 03:31 PM - edited 05-10-2017 03:34 PM
Kevin, you may be right. My model was based on the brute force approach, which the compiler-optimizer will smooth over and not make copies where unneeded.
This Paper offers some facts, but seems a bit scattered.
The New Data Value Reference node takes any data as input and creates a reference to the data. Note that copying can still occur if the data is forked and used elsewhere.
OK, there's support for your idea that the NEW DVR function itself makes a copy somewhere and that copy is what you get a reference to.
There's also support for that in the fact that you can make a DVR to a constant, and that you are warned to DELETE DVR when done to avoid memory leaks. If it did NOT make a copy, then it wouldn't matter whether you DELETE DVR or not.
Then there's this:
With a new Preserve Run-Time Class.vi primitive, LabVIEW can guarantee runtime type consistency that you can use to swap two values. If you need a class reference that lets you change the underlying object, create a reference to a cluster of the class. This gives you the ability to swap values at the cost of hierarchical casting.
I don't know what that's supposed to tell me. As I have learned, the NEW DVR makes two NEW instances of the GRAPHIC class, each containing the same data.
Then you dereference them both to get a GRAPHIC, but you can't swap them without the PRTC because.... I don't know what.
I don't think the pic refers to the statement right before it: If you need a class reference that lets you change the underlying object, create a reference to a cluster of the class.
The pic is not doing that.
Blog for (mostly LabVIEW) programmers: Tips And Tricks