Jump to content

Equality checks on objects


Recommended Posts

I discovered something today that makes perfect sense when you think about it but isn't immediately obvious. (Well, it wasn't obvious to me...)

When using the equals prim on by-value objects LV does a value comparison. If I have two completely separate objects whose private data values are the same, the equals prim returns True. On the other hand, doing an equality check on two by-ref objects with the same values in the private DVR returns False unless they both dereference to the same private data cluster. (i.e. The DVR refnums are the same.)

In other words, the equals prim is smart. It "knows" to compare values of by-val objects and to compare references of by-ref objects.

...eh, I thought it was a neat side effect.

  • Like 1
Link to comment

I'm so proud of the little Equals prim.

laugh.gif I hope you have the requisite pictures of it hanging in your cube. wub.gif

------------------

I did discover a gotcha while goofing around with it last night. By-ref objects need to initialize the DVR before the object can be used. Comparing a pre-initialized by-ref object with a post-initialized by-ref object returns False. Again, it makes sense if you think it through; however, I think it is counter-intuitive and it requires fairly deep Labview knowledge and under-the-hood understanding for it to make sense.

The rule-of-thumb for by-val objects is "branching always makes a copy." (We know that's not always true, but it's a useful way to explain the behavior to new users.) The rule-of-thumb for by-ref objects is "branching always refers to the same object." Now we have to throw in the caveat, "unless you haven't initialized your by-ref object." It's as if by-ref object constants on the block diagram aren't objects at all, but are classes instead. Before LV'09 you couldn't put classes on a VI--only objects. Now you can, and they look suspiciously like objects.

It can be particularly perplexing for class users if, like me, you try to simplify the class by initializing the DVR at runtime on an as-needed basis.

post-7603-125492710988_thumb.png

In those cases, simply reading a property will lead to unexpected results for the new LOOPer.

post-7603-125492858957_thumb.png

Link to comment

In other words, the equals prim is smart. It "knows" to compare values of by-val objects and to compare references of by-ref objects.

...eh, I thought it was a neat side effect.

I'm not sure its is that smart. It basically just typecasts the ref to a U32 (or maybe an I32) and compares the values. It does the same for VISA and IMAQ sessions. If you think about your uninitilaised references, the value when typecast is 0 which is not equal to its value if its initilaised.

Edited by ShaunR
Link to comment

Isn't that what you'd expect?

Its what I expect since I think of refs similarly to pointers. An unitialised pointer is a "null" pointer (no memory allocated). But I think Daklu thinks of them as references to objects and that by placing it on the diagram the "pointer" is allocated. So I got the impression (rightly or wrongly) that he expects a reference to an uninitialised ref to be the same as an initialised one since it is the same object. In that respect. Daklus last image seems prefectly normal to me, however it is an "unexpected" result.

Edited by ShaunR
Link to comment

I'm not sure its is that smart.

Yeah, I understand it's not really 'smart' and the behavior is just a side effect of the way LV stores references and the by-val nature of testing for equality.

But I think Daklu thinks of them as references to objects and that by placing it on the diagram the "pointer" is allocated. So I got the impression (rightly or wrongly) that he expects a reference to an uninitialised ref to be the same as an initialised one since it is the same object.

No, I don't expect it to behave that way. Before now I hadn't really given it much thought as I never had to do object comparisons, but the behavior does make sense to those well-versed in how LV works. I do wish it were possible to create auto-initializing classes (without crippling other basic class capabilities by wrapping it all in a library and making it private.)

Part of my job is figuring out APIs for various internal reusable components. The long-term goal is to create APIs that are easy enough for new(ish) Labview users to understand, so they have the tools to quickly put together simple test scenarios. I've been struggling with a way to encapsulate the complexity and present a uniform experience to the user. Reference classes (by which I mean classes that contain any refnum that must be initialized at run-time) are necessary for lots of advanced behavior, but it is difficult to wrap them in a package that is intuitive to use.

Daklus last image seems prefectly normal to me

I submit that the only reason it seems perfectly normal to you is because I revealed information about the implementation. Specifically, I explained that it is a by-ref object and told you where the DVR initialization was taking place. Had I presented it as a normal by-val object the results would not have made any sense whatsoever.

I think that's part of the problem... By-val classes and by-ref classes are fundamentally different beasts, with different behaviors across a wide range of operations, yet to the average user they look identical (subject to the class designer's icon making skills) and at design-time they behave identically. By-ref object cubes on the BD aren't really "objects" in the sense that they are ready to be used. They behave more like a traditional class definition--the user still has to "create" (i.e. initialize) the object before it can be used.

Are there any other BD constants in Labview that have to be initialized at run time before you can use them? (Honest question... I can't think of any off the top of my head.)

-------------------

[Note - I didn't start this thread with the intent of bridging even a little bit into the topic of constructors auto-initializing classes. Yet the more I work with reference classes the more uneasy I become with the toolset we have for managing them. I have this nagging voice in the back of my head telling me that it could be much simpler. (Maybe it's Evil AQ again... wink.gif )]

Link to comment

Doesn't it come down to the fact that by-reference objects are really references to by-value objects and all references in LabVIEW basically behave the same?

In my mind I prefer to think of DVRs as reference to something and sometimes those things happen to be (by-val) objects; I don't think of by-ref objects to be a unique type of data type in LabVIEW.

Link to comment

Doesn't it come down to the fact that by-reference objects are really references to by-value objects and all references in LabVIEW basically behave the same?

In my mind I prefer to think of DVRs as reference to something and sometimes those things happen to be (by-val) objects; I don't think of by-ref objects to be a unique type of data type in LabVIEW.

I responsed here.

Link to comment
  • 4 years later...

I just got burned on the X != X, if X = NaN.  Since NaN is never equal to NaN  (see "Comparison of Two NaN Constants Returns FALSE in LabVIEW" on ni.com)

 

 

Along the lines of this thread, though, I found it interesting that, oh, unless that NaN is in the data of an object.  Then NaN is equal to NaN  (x=y?). 

 

....Unless you make a copy of the object (x=y? 2):

 

post-16779-0-48623700-1384354867_thumb.p

Link to comment
I found it interesting that, oh, unless that NaN is in the data of an object.  Then NaN is equal to NaN  (x=y?). 

 

....Unless you make a copy of the object (x=y? 2):

 

I'm guessing that this is an optimization - if the equals node sees the same object wire going into both terminals, it probably says "I don't know how long a comparison will take, so I will just return true, since I'm comparing the same object". I think it's a slightly weird optimization, if only because the use case of wiring the same object twice into the node is ridiculous, but that's my guess based on the image. Of course, it also seems to produce inconsistent results in the case of an object containing a NaN, so this can probably be considered a buggy optimization.

Edited by Yair
Link to comment
I just got burned on the X != X, if X = NaN.  Since NaN is never equal to NaN  (see "Comparison of Two NaN Constants Returns FALSE in LabVIEW" on ni.com)

Yup, I'd say this is one of those "Everyone makes that mistake the first time" type is situations.  I just want to know if my number is NaN so I wire it to an equal and put a constant of NaN right?  Nope use the primitive under the comparison palette "Not a Number/Path/Refnum"

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.