Jump to content

Magical variant to data? Or bug?


Recommended Posts

One of my minions is working thought the online Core3 course and showed me some code that made no sense to me. I am wondering it this is a bug or some little known feature.

In the code, he was told to wire a variant to the 'variant to data' function and wire in a path constant so the output would be a path. This was later wired to a function needing a path input. So far so good. But later in the same code (in a different case) he was instructed to do the same thing but this time there was no input to the 'variant to data' function to tell it what to cast the variant data to. But for some reason, the output was still a path and he could still wire it to another function that needed a path as input. Here is a screen grab of the magical code:

post-2411-0-51093000-1348769082.png

So, what is going on here? Bug?

Link to post
Share on other sites

My vote is bug, but I've never seen this.

Is it possible for you to post the VI? I'm curious to see if this works with other data types or somehow just is convinced a path is wired to the missing Type terminal.

I guess theoretically this could be a feature, if all of the sink nodes are the same data type. But since NI hasn't done it yet I'm guessing it is a difficult feature to implement, but I would love to have a polymorphic VI change it's type based on an output that's needed, as well as its input.

Link to post
Share on other sites

My gut says "BAD. Prone to abuse." I'm going with my gut on this one.

What if the required output type changes, and it's way downstream? You won't get an error until you run. This should be a development-time error, not a run-time one.

(Also, anything that AQ calls "magical" scares me :) )

Edited by jaegen
Link to post
Share on other sites

Well given that this 'trick/feature' was used in the Core3 materials and WAS NOT EXPLAINED, it is going to lead to misuse and abuse. When my coworker asked me to explain it, I could not and told him he was right to think this was bad form. I prefer any such operation to be explicit. The implicit nature of this will lead to confusing bugs in the future.

Link to post
Share on other sites

Well given that this 'trick/feature' was used in the Core3 materials and WAS NOT EXPLAINED, it is going to lead to misuse and abuse. When my coworker asked me to explain it, I could not and told him he was right to think this was bad form. I prefer any such operation to be explicit. The implicit nature of this will lead to confusing bugs in the future.

So I understand the abuse side of things for sure, but anything can be abused right? If there is proper documentation, and training (which it sounds like there isn't) then I don't see anything wrong with this feature.

Should every polymorphic VI not have the "Automatic" option when choosing the type based on the inputs? Should we have to be explicit about that as well? What about Data To Variant, should I have to tell it, hey this is a string and you should convert from string to Variant. I understand this example is weak given that it is a primitive and accepts all data types.

Link to post
Share on other sites

So I understand the abuse side of things for sure, but anything can be abused right?

On the "abusable" spectrum, this ranks more toward the "asking for problems" side. :P

Should every polymorphic VI not have the "Automatic" option when choosing the type based on the inputs?

That's a little different, since it's downstream vs. upstream type propagation, and sources-to-sinks is one-to-many.

Link to post
Share on other sites

That's a little different, since it's downstream vs. upstream type propagation, and sources-to-sinks is one-to-many.

I agree so I'll just post what I'm thinking.

I want this functionality for my own code so I can use (and likely abuse) it.

Edited by hooovahh
  • Like 1
Link to post
Share on other sites

Feature. That kind of magical backpropagation is rare in LV but a few nodes have implemented it. There's a lot of internal debate about how good an idea it is. Myself, I would rather the type terminal be a required input.

Another thought on this matter: a broken run-arrow is your friend; the mentality of "avoid the broken run-arrow" to justify language features feels flawed (think: "auto-insert feedback node into cycles").

A broken run-arrow and strong, explicit typing is like a friendly heads-up at compile-time saying "you did it wrong". Compare this to the insidious manifestation of a run-time error, or even worse, unexplained or quirky behavior with no error, inadvertently introduced by automatic code mutations. The compiler constantly validates all syntax (yay!), whereas run-time, it's not so easy to exercise every execution path to flush out the bugs.

  • Like 1
Link to post
Share on other sites

I didn't know you could do that, neat.

I don't see the problem though. I'm assuming you'd get an error if the other side of the sink couldn't resolve to a static type (polymorphic VI, an input that adapts to type, or an object)?

Link to post
Share on other sites

Although this "feature" is kind of cool, I believe the usage is a bit limited.

What I do find magical about this function, however, is the following construct. Before discovering this trick I wrote a lot of unnecessary for loops.

post-26690-0-26316600-1348802032.png

Edited by Darin
  • Like 1
Link to post
Share on other sites

What I do find magical about this function, however, is the following construct. Before discovering this trick I wrote a lot of unnecessary for loops.

I love this trick. Related to this, Variant to Data will also convert a variant that contains an array into an array of variants, which is sometimes useful.

Personally I think the compiler should infer (or propagate) types as much as possible, so I don't see it as a bug. There's always a risk of passing an incompatible type when using variants - it's the price of using a non-specified type in a strongly-typed language - and it's the programmer's responsibilty to manage that risk. This doesn't prevent you from wiring the type input, if you want that check at compile-time, it just makes it optional for those situations where you don't need it and don't want extra constants on the block diagram.

Link to post
Share on other sites
  • 4 weeks later...
  • 1 year later...

I agree so I'll just post what I'm thinking.

I want this functionality for my own code so I can use (and likely abuse) it.

Well almost two years later and guess what, I have found how to replicate this functionality, and abuse it to my liking.  I just submitted a code repository for a Variant Repository which is basically reading and writing variant attributes with some added functionality.  The read function has the ability to look at the data type that the output is wired to, and change the type to that.  

 

Doing this was relatively easy using XNodes and the Adapt To Inputs ability.  It gets the reference to the output terminal, then gets the reference to the sink location of the wired tied to it, then gets the data type of that terminal.  It will default to a Variant if it has issues in this operation.  The performance of using this is basically nothing because all it does in my case, is change the type of a constant on the block diagram of my XNode.

Link to post
Share on other sites

Well almost two years later and guess what, I have found how to replicate this functionality, and abuse it to my liking.  I just submitted a code repository for a Variant Repository which is basically reading and writing variant attributes with some added functionality.  The read function has the ability to look at the data type that the output is wired to, and change the type to that.  

 

Doing this was relatively easy using XNodes and the Adapt To Inputs ability.  It gets the reference to the output terminal, then gets the reference to the sink location of the wired tied to it, then gets the data type of that terminal.  It will default to a Variant if it has issues in this operation.  The performance of using this is basically nothing because all it does in my case, is change the type of a constant on the block diagram of my XNode.

 

Did you mean to add "penalty" or something there?

Also, I decided to give this a try myself. Here's an XNode I made that's basically the type cast function, only it implements the behavior described in the thread. (I actually got the idea to do this in an XNode before I noticed hooovahh's post; maybe he hadn't posted it yet.) A couple warnings though: one, I haven't tested it that much, and two, it uses a private method in the GenerateCode ability to create a constant of a given type. No idea why this method is private; I don't see any problems using it can cause, but I'm warning you because I imagine it's marked private for a reason.

 

Also, if you right-click it, there's an option to replace it with a regular typecast node along with a constant of the proper type.

 

Auto Typecast.zip

Edited by flarn2006
  • Like 1
Link to post
Share on other sites

Although this "feature" is kind of cool, I believe the usage is a bit limited.

What I do find magical about this function, however, is the following construct. Before discovering this trick I wrote a lot of unnecessary for loops.

attachicon.gifVariantToArray.png

 

This is not the same thing. Variant to Data can very well deal with arrays and even clusters as long as the data structure inside the variant is actually compatible. That doesn't even mean it needs to be exactly the same. LabVIEW will happily convert numerics and timestamps, etc inside the variant, into strings. It will only joke on fundamentally incompatible elements and some that are debatable if it should still attempt a conversion.

 

On the other hand, the conversion from timestamp to string, or floating point to string for instance will use the platform specific formatting rules (system setting dependent). That is often not what one wants when it's meant for more than just display purposes. But LabVIEW hasn't a runtime mind reading interface (yet) :D .

 

As to the original topic, I'm not sure I like it. The lazy dog in me says: sure it's fine! but the purist prefers explicit type definition for such things. Call Library Node is another function that also does attempt back propagation of types for "Adapt to Type" terminal, but this usually fails as soon as there is any structure border in between. And it can indeed cause nasty problems if one changes the datatype of a control downstream the wire without even a warning indication of a change to the Call Library Node configuration and suddenly the application crashes nastily.

Link to post
Share on other sites

Did you mean to add "penalty" or something there?

Yeah that's what I meant.  There is no run-time penalty, because at development time is when the constant is made.

 

 

Also, I decided to give this a try myself. Here's an XNode I made that's basically the type cast function, only it implements the behavior described in the thread. (I actually got the idea to do this in an XNode before I noticed hooovahh's post; maybe he hadn't posted it yet.) A couple warnings though: one, I haven't tested it that much, and two, it uses a private method in the GenerateCode ability to create a constant of a given type. No idea why this method is private; I don't see any problems using it can cause, but I'm warning you because I imagine it's marked private for a reason.

Yup this is similar to the Variant Repository I posted.  Not sure why that method is private either but I couldn't find a better way to make a constant.  Your code does also fall short if there is no data associated with the sink yet.  I know you said you didn't test it much so that's fine, but you don't handle if you wire the output to the tunnel of a case structure for example.  The data becomes void, and you get an error popup.  My implementation looks for error and defaults to a variant data type if one is seen in the process of finding the sink data type.

Link to post
Share on other sites

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.

  • Similar Content

    • By Jim Kring
      [Update: NI Bug 974336]
      There seems to be a bug in the coercion of data to variant when a cluster contains a single element that is a variant. (original post here).
      Note: This bug appears to be very old, going as far back as LV2012. This has been reported to NI in the LV2020 Beta forum. I don't have a Bug ID / CAR yet.
      Coerce to Variant Fail (LV2019).vi


       
      Note that adding another element to the outer cluster causes the problem to go away.


    • By ShaunR
      Maybe others have seen this but I only became aware of it recently so I apologise if there is already a CAR for it.
      The following demonstrates a difference in behaviour between LabVIEW 2017 and previous versions (back as far as 2009, maybe further).
      The VI registers an event when it starts (in the timeout case) and generates a user event when the Increment button is pressed.
      The expected behaviour is that the counter will increment by one every time the button is pressed. This is the case for LabVIEW versions prior to 2017. In 2017, the user event is never fired, nor is there an error emitted by the generate user event.
      To get the VI to operate as expected in 2017; change the event refnum tunnel to a shift register. This seems to indicate that the refnum prototype is stomping on the dynamically allocated reference whereas in previous LabVIEW versions it would not. Note also, that when using the shift register, the cases do not need to be "wired through" as would be expected with similar functionality in a normal case statement.
      evnt.vi
    • By Taylorh140
      So sometimes when you do protocol decoding it is convenient to use a variant to store decoded data. For example you might have a 2 bit enumeration that is decoded like this:
      00 -> Good
      01 -> Bad
      10 -> Ugly
      11 -> Catastrophic
      If you cast the value to an enumeration that contains these values before hand you can see them on the variant control. If you use a Ring you will only see a value. 
      I know that the LV flatten to string contains the enumeration strings but the encoding is a bit of a mystery, although it looks like the openg palette has figured some of it out to some degree. But to me it doesn't look like there is any reason i couldn't generate an enum to use inside the scope of a variant. Has anyone done this, or know how to generate the string for this purpose. 

    • By Taylorh140
      After working on the set cluster element by name xnode, it made me realize i could use the same concept to convert a variant array to a cluster. The technique is actually pretty simple, the xnode generates a case structure for each element in a cluster in cluster order, wherein a bundle by name is used to set the value and an unbundle by name is used to get the type, a variant to data is used to convert the data. This has some benefits over some methods, you are not limited to 255 elements, although that is not usually the case some of us are paranoid that clusterosaurus giganticous will be larger than expected. It also has a draw back  that is that when converting from a variant array all the elements must have unique, non-blank names, and this is usually the case. 

      I think this technique (though very brute-force) might be useful for some other things let me know what you guys think.

      VariantArrayToCluster.zip
    • By A Scottish moose
      Hey everyone,
       
      I am working on a backup function for a test executive.  The backup uses the 'class to XML' vi to create an XML string and then save it to a file to be reloaded later. All of my test specific information lives in the class (or one of it's children).  I like this functionality because it makes backup and reload brainless.  It just works.... until now... I've got a test class for my current tester that's grown rather large.  Everything works fine, until the tester loads some waveform data into either of the waveform arrays.  Without data in this field the class reloads just fine, otherwise if fails and says the XML is corrupted.
       
      As you can see in my backup vi I have built in a work around that flattens the waveform arrays to strings, drops them back into the class private data, deletes the waveform arrays and then writes the class.  This works! Much to my surprise both waveform data and the rest of the class data are written to file and reloaded without error.  
       
      Does anyone have any knowledge or experience with this? 
       
      Cheers,
       
      Tim


×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.