LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
thutch79

Compare Variant Types

Status: New

The variant data type parsing palette is great when you have to deal with passing variants around. However, there is one call that would be super useful. If I have two variants, I'd like to know if they are of the exact same type. The type information only tells you so much. For example, if you have an array in the variant, it will only tell you it's an array, not a double float array, or a waveform array.

 

I've wrote a version of this that does it, but I'm not sure I cover all the edge cases. NI would be much better suited to ensure it covers all the potential typing possible and can likely make it more efficient than I could. But, I think this implementation solves this issue for most common data types and even some more exotic things that could be in a variant. I would love to see this included in the variant data type parsing palette.

Screen Shot 2020-08-13 at 8.56.41 AM.png

In this example, I'm using it to check an array of variants to filter out ones of type I32.

20 Comments
wiebe@CARYA
Knight of NI

>I may not catch every obscure type possible, 

 

Spoiler

 I think there's a problem with arrays in your VI. A 1D array will match any nD array of the same element type. Should be an easy fix (check dims)...

 

Enums that aren't type defs seem to be a problem. Their elements should be checked.

 

The while loop in the Cluster could be a for loop with auto indexing. The sizes are already checked.

 

It would probably look totally different if I made it.

 

More to the point; there are some assumptions that you've made.

 

For instance, I'd say the types match even if one is a type def, and the other isn't. EDIT: You seem to have that covered.

 

Depending on the exact purpose, there will probably be more 'opinions'. Two of more those opinions will make it very hard to make a single VI that pleases all...

thutch79
Active Participant

Yes, I did cover the type def absolute match optional flag, but that doesn't mean there aren't other edge cases I'm not thinking of. I appreciate this discussion because it has been eye opening to how complex a seemingly simple request like this is. Writing a function like I did is all well and good, but documenting how you should expect it to behave given various conditions might turn into an endless nightmare.

AristosQueue (NI)
NI Employee (retired)

LabVIEW's C++ code has two different ways to compare type descriptors. The first is a very old function that has a hardcoded traversal built into it and a int32 that is a bitset of options. We ran out of bits! The second is a traversal routine where the caller provides the comparison routine to make decisions on a step-by-step basis on what to return for the comparison and whether to continue the comparison. It's much harder to use than the bitset version, but far more flexible. Tradeoffs.

 

To give you some understanding of all the ways that type comparison has to be varied, here's information about the older comparison function.


The return is also a bit set. No bits set means the two types are identical. About 1/3 of the bits are "s____" bits, which is some sort of legit coercion. The others are "x____" bits, which is a type conflict of some sort. The special value "sFakeConv" indicates a type difference but which is not considered a real coercion of the data for various reasons.

  • No bits set default behavior. Ignore all name differences. Typedef name or timestamp differences reported as sCvtSign. Most other differences reported as some x___ flag.
  • AllNameChk Any name differences reported as xName.
  • SubNameChk Names below top-level of type desc must match exactly
  • TypeDefChk typeDefness or typeDef name or stamp differences reported as xType
  • NoTypeDefChk typeDefness or typeDef name or stamp differences ignored entirely.
  • NoFixBndChk ignore fixed/bound size differences
  • NoFuncIPChk ignore in-place differences between functionCode TDs (i.e. between conpanes of VIs)
  • TDAttribChk attribute bits in type code must match exactly [Attribute bits are not exposed to G code level.]
  • NoFixedPtSubtypeChk ignore fixed-point subtype differences
  • ProbeChk ignore differences between wire and generic probe types. For example, between refNum and uL, between queue and string, between enum and uL, and between LVClass and cluster. Others may be added over time.
  • StrictRefnumTagChk require an exact match on the refnum and tag parts of a refnumTag TD, regardless of what the rch file indicates for coercion.
  • ReportCvtTypedefChk If there is a typedef difference, report it as sCvtTypedef instead of sCvtSign.
  • ReportUpcastAsFakeChk If there is a refnum upcast difference, report it as sFakeConv instead of sConvert .
  • BoolIsUB treate boolU8 as bool ['boolU8' is obsolete type since LV5.0]
  • ConvertChk asymetrical compare, "Can left be converted into right?" Causes many x___ to become s____.
  • VarConvertChk allow conversion to and from LV variant
  • NoTimestampChk ignore timestamps in typedef type descriptors
  • MoreComplexChk Is tdRef more complex than td? [I'm not even going to try to explain this one.]
  • IgnoreMDTWrap ignore waveform wrappers (treat like cluster)
  • DispatchChk test function parameters for dynamic dispatch compatibility (allows type differences in the dynamic dispatch terminal)
  • PolyUnitCvtChk ignore unit conflicts when converting to polymorphic units
  • IgnoreTopLevelTypeDef ignores the typedef on the top level type descriptors during a recursive call to Compare. Nested typedefs follow the other bits.
  • CompareAggregates same as default, except that waveforms and Express Dynamic type (that weird dark blue wire that most of you have never seen) have special, more restrictive rules
  • FuncTDInvokeChk Used to compare whether a subVI node on a diagram is compatible with the subVI being invoked.
  • SmartProbeChk ignore differences between enum and uL of same precision (for smart probe)
  • NoFuncSubTypeChk ignore subtype and prealloc bounds differences between functionCode TDs if subTypeSubVIInputsEnabled
  • CompareForCopy comparing types for copy
  • NoFixBndSubChk ignore differences in fixed and bounded array sizes.
  • GenericnessChk obsolete
  • EphemeralChk compare ephemeral bit of attributes only [Not exposed to the G code level. Ephemeral bits are only set while we are resolving type prop in loops to settle shift register types correctly.]
  • NoAutomaticDowncastChk ignore differences between functionCode TDs that come from automatic downcast relationships among the terminals.
  • NoOMIdChk OMIds carry the type information of refnums. Ignore all differences in refnum types. In other words, allow a control refnum to be considered to be the same as a queue refnum. Comes up when treating the refnums as int32s for purposes of copying/comparing data.
  • OMIdClassOnlyChk When comparing refnum OMIds (see previous bullet), only compare class info. So a control refnum and a queue refnum are different, but a control refnum for a numeric and a control refnum for a bool are the same, and a queue of bool and a queue of string are the same.

I don't know if that helps any of you, but I thought it might be interesting fodder for this brainstorm thread.

wiebe@CARYA
Knight of NI

>I don't know if that helps any of you, but I thought it might be interesting fodder for this brainstorm thread.

 

Yes, that helps (me 😁). This function is actually available to 'insiders'... But the flags are not documented. Until now. EDIT: Although most descriptions are very cryptic...

 

Not sure how safe this function is. Guess it's for 'those who know' for now...

thutch79
Active Participant

wiebe@CARYA.... I do check the array dimension size. Honestly, I may have fixed that after the initial post, I'm not sure.

Screen Shot 2020-09-16 at 10.40.18 AM.png

You may be right about the while loop for clusters. I lifted that from another VI in the variant typing palette, but yes, since I check the sizes match already, a for loop is safe and a better choice.

thutch79
Active Participant

This is kind of an aside, as I have already said Variant to Data does not cover what I'm looking to do. As to the lost data issue with using "variant to data", I discovered something interesting. Yes, "variant to data" does happily convert any numeric it can coerce without error. However, the in-place structure seems to be much more strict about what it will convert.

Screen Shot 2020-09-16 at 10.47.49 AM.png

[edit] Sorry, I should have labelled those constants. The large number is an I32 and the constant zero is an I8.

wiebe@CARYA
Knight of NI

>wiebe@CARYA.... I do check the array dimension size. Honestly, I may have fixed that after the initial post, I'm not sure.

 

Think that one's on me too.

wiebe@CARYA
Knight of NI

>This is kind of an aside, as I have already said Variant to Data does not cover what I'm looking to do. As to the lost data issue with using "variant to data", I discovered something interesting. Yes, "variant to data" does happily convert any numeric it can coerce without error. However, the in-place structure seems to be much more strict about what it will convert.

 

That is interesting, but not very useful for our purposes here. It will only work with hard coded types. In other words, there's no way to make a VI that accepts a variant to compare it with another variant.

 

It would work in a .vim, but for this specific problem it would still require all types to be hardwired to the .vim at some level.

 

The .vim could be useful as a check for "variant vs exact type". Maybe it is maybe faster than variant tools that are available (that call a dll)? Perhaps the same dll is called anyway. It seems to be ignorant towards typedefs... 

avogadro5
Member

There are a few VIs in vi.lib that seem to help with the issues in this thread:

avogadro5_0-1694042365984.png

This check returns False when you for instance have a u32 and i32 in the same position in clusters for both variants, and depending on whether you care about element names you can have "Retain Internal Names" as true. Most people probably don't care about the top-level name as mentioned above.

 

They of course don't show up on the palette, and only work because of what appears to be a very lightly documented feature which is they both return the *default value of the type* (in other words they throw out the value part of the variant you pass in).

 

I found that the variant "Equal?" node sometimes marks type variants as equal when I wouldn't, but if you flatten to a string (either with "Flatten to String" or "Variant to Flattened String" and then use the type string) you get pretty good results.

wiebe@CARYA
Knight of NI

>I found that the variant "Equal?" node sometimes marks type variants as equal when I wouldn't, but if you flatten to a string (either with "Flatten to String" or "Variant to Flattened String" and then use the type string) you get pretty good results.

 

Until you put references in the variants.

 

Variants can have attributes. They don't end up in the flattened data. Should they be equal if the attributes are different or not? (Answer: as always, it depends...)