Jump to content

compare objects in search 1-D array


Recommended Posts

How can I programmatically compare objects (without comparing the object data)?

In my case I have one class in which I initialize a number of objects and insert these into an array. The array is of type "Parameter" class and the elements are objects corresponding to child classes of "Parameter" representing individual parameters (e.g., AirTemperature, BarometricPressure, etc.). This allows me to autoindex the array in a for loop when I want to run a common method (well, usually with dynamic override methods) for each parameter.

Sometimes, however, I need to retrieve a specific parameter from the array. I tried using an object constant as the search element input in "Search 1D Array" and this works if I have not initialized or otherwise altered the array objects. If, on the other hand, I have initialized the objects or otherwise changed the data in the objects the comparison method within "Search 1D Array" does not find a match. (The comparison method doesn't compare what I want it to compare.)

How do I compare objects without comparing their data?

Link to comment

QUOTE(Paul_at_Lowell @ Jul 17 2007, 09:54 AM)

How can I programmatically compare objects (without comparing the object data)?

Sometimes, however, I need to retrieve a specific parameter from the array. I tried using an object constant as the search element input in "Search 1D Array" and this works if I have not initialized or otherwise altered the array objects. If, on the other hand, I have initialized the objects or otherwise changed the data in the objects the comparison method within "Search 1D Array" does not find a match. (The comparison method doesn't compare what I want it to compare.)

How do I compare objects without comparing their data?

Search 1D Array will not work unless the object (including the object data) is an exact match (someone else can let me know if I'm wrong but I believe that is correct). It looks like you are actually searching for an object of a particular type... so why not try type casting the object until you don't get an error (use 'to more specific class' from the application control palette).

Link to comment

QUOTE(Paul_at_Lowell @ Jul 17 2007, 05:54 PM)

How can I programmatically compare objects (without comparing the object data)?

In my case I have one class in which I initialize a number of objects and insert these into an array. The array is of type "Parameter" class and the elements are objects corresponding to child classes of "Parameter" representing individual parameters (e.g., AirTemperature, BarometricPressure, etc.). This allows me to autoindex the array in a for loop when I want to run a common method (well, usually with dynamic override methods) for each parameter.

Sometimes, however, I need to retrieve a specific parameter from the array. I tried using an object constant as the search element input in "Search 1D Array" and this works if I have not initialized or otherwise altered the array objects. If, on the other hand, I have initialized the objects or otherwise changed the data in the objects the comparison method within "Search 1D Array" does not find a match. (The comparison method doesn't compare what I want it to compare.)

How do I compare objects without comparing their data?

If I understand correctly you are trying to search for objects by class rather than by value ? You have an array of class A and are looking for which elements of that array are in fact class B objects where class B is one of a number of child classes of A ? You can use the "to a more specific class" node to test whether an object can be cast to a specific child class. You'd need to write your own set of search sub-vis though.

(edit - oh the joys of fast answers - I see Omar Mussa beat me to it !)

Another approach you could follow would be to have a dynamic method called e.g. Class_Name that returns a string containing the name of the class. You then override this in every child class, loop through your array of parameters calling Class_Name, do a regular search on the resultant array of strings and then index the array of objects to retrieve the specific class.

One of my wishlist items would be a function in LV that returns the class name (or even better a reference) to the actual "on-the-wire" class.

Link to comment

You all are very fast!

This method works fine. To search a 1D array I try to cast each element to the class I am seeking within a while loop. The no error case indicates a match.

Thanks a lot! I was stuck on this!

Link to comment

Actually it's a recurring problem to select action based on what class your object is of. Consider for example that you receive a message object from some message source and you need to make a decission of next action based on the message type. The typecasting trick works fast and very well when there are only one or few classes you need to match agianst or message types in our example case. However when the number of cases increases, the code becomes easily a messy as you need first to check if the message is of type A and then to check if message is of type B and so on.

Classes that use OpenG Class Templates for LabVIEW Object-Oriented Programming can take advantage of OpenG Object method "MatchRuntimeType". This particular method allows users to easily check if the object is of some known type and select action based on the matched type. This functionality is called Pattern Matching in object-oriented programming.

In the image below the user has some object which is Child B in this particular case. In the code, the user needs to select action based on the type of the class. Using MatchRuntimeType method of OpenG object, this particular task is very simple. User simply needs to create a type array of all classes for which there is a different action and wire the type array to MatchRuntimeType together with the object of unknown type. MatchRuntimeType returns the index of the first class that matched the object. Parent class matches all it's child classes. If no matches were found, -1 is returned. The returned index can then be wired to case structure to select action based on the matched class.

http://forums.lavag.org/index.php?act=attach&type=post&id=6381

Note that this method requires that all classes are based on the OpenG Class Templates.

Link to comment

You're facing the same problem that an array of clusters faces when you want to search for a cluster based on a single field instead of the entire cluster. The only way around it in LV is to write a new Search 1D Array that checks for whatever criteria it is that you're searching for (you can write this generically and then take a VI Server refnum to provide the comparison routine, too). This has been done by many people and I think there are implementations of it on LAVA somewhere.

Link to comment

Well, there is another topic on this board (http://forums.lavag.org/Finding-out-LabVOO...lass-t5220.html) that in part describes the class coding and the differences between the root LabVIEW Object class and developer-created classes. I'm not sure there's quite enough information there to figure out how to do the comparison reliably (not just by class name, but perhaps application instance and certainly by namespace as well).

By the way, it is not sufficient just to compare the "data string" output of "Flatten To String" because the data is encoded in the data string. (We have the same problem the built-in Search 1D Array method has.) We have to extract the information we need from the data string (as Gavin has done in his solution). Is the class name the only information we need for the comparison?

I looked for more information on LAVA but haven't found it yet....

Link to comment

QUOTE(Paul_at_Lowell @ Jul 18 2007, 11:19 AM)

By the way, it is not sufficient just to compare the "data string" output of "Flatten To String" because the data is encoded in the data string. (We have the same problem the built-in Search 1D Array method has.) We have to extract the information we need from the data string (as Gavin has done in his solution). Is the class name the only information we need for the comparison?

Pop up on the Flatten To String node and select the LV 7.x compatibility mode. This gives causes the node to add a type descriptor output. You can then compare the type descriptors for equality. Note, this allows to test for *equality* ... it won't help if you're looking for "this class or any child of this class."

Link to comment

QUOTE(Tomi Maila @ Jul 17 2007, 12:18 PM)

Classes that use OpenG Class Templates for LabVIEW Object-Oriented Programming can take advantage of OpenG Object method "MatchRuntimeType". This particular method allows users to easily check if the object is of some known type and select action based on the matched type. This functionality is called Pattern Matching in object-oriented programming.

OK, I downloaded the VIPM, the OpenG Class Templates, and Endevo's GDS community edition. (It's all pretty impressive, by the way.) I configured OpenG100 as the class provider. I don't see (nor can the Function pallete search find) the "Match Runtime Type" function/method. Where do I find it?

QUOTE(Aristos Queue @ Jul 18 2007, 11:15 AM)

Pop up on the Flatten To String node and select the
LV
7.x compatibility mode. This gives causes the node to add a type descriptor output. You can then compare the type descriptors for equality. Note, this allows to test for *equality* ... it won't help if you're looking for "this class or any child of this class."

OK, I retrieved the type string from the 7.x version, which returns an array. I need to compare some of the elements in the type string array, not all, though. (If I include all the comparison shows a mismatch as before.) How do I know which elements are necessary and sufficient?

Link to comment

QUOTE(Paul_at_Lowell @ Jul 18 2007, 05:19 PM)

Well, there is another topic on this board (http://forums.lavag.org/Finding-out-LabVOOP-object-runtime-class-t5220.html' target="_blank">http://forums.lavag.org/Finding-out-LabVOO...lass-t5220.html) that in part describes the class coding and the differences between the root LabVIEW Object class and developer-created classes. I'm not sure there's quite enough information there to figure out how to do the comparison reliably (not just by class name, but perhaps application instance and certainly by namespace as well).

Ahhh, I'm reinventing the wheel.... actually that thread provides a lot of useful information. I've edited my original post with a new version of my class namer tool that extracts more information from the class reference and (I think) now includes enough to properly test the class identity. Although I coded from the information in the thread, it's actually very similar to the OpenG Object template version except mine handles the special case of the base class which the OpenG oibject template don't have to worry about.

I'd now revise my wish list for the possibility to access the class heirarchy in the runtime so we could do whatever testing of class hiearchy that we wanted to. (Actually I notice that you can wire a LabVIEW class to a property node - it would be very cool if we could expose the class hiearchy through the property nodes - it would be even cooler if we could write custom properties like in XControls - it would be a nice way of creating pseudo public/protected data instead of get/set methods.)

Link to comment

QUOTE(Paul_at_Lowell @ Jul 18 2007, 10:36 PM)

OK, I downloaded the VIPM, the OpenG Class Templates, and Endevo's GDS community edition. (It's all pretty impressive, by the way.) I configured OpenG100 as the class provider. I don't see (nor can the Function pallete search find) the "Match Runtime Type" function/method. Where do I find it?

When working with LVClasses, all classes used need to be added to the project. LabVIEW doesn't automatically do this for you, not even when some classes you already have in the project inherit from some parent classes. So you need to manually add the parent classes to the project. The classes you need are under path <user.lib>\_OpenG.lib\openg_object. Simply add OpenG Object to the project. Then once in project, open the class and you'll see the available methods.

I'd really like to see LabVIEW to automatically add the available methods for particular class to the context menu of a class wire. AQ, are we seeing this anytime soon?

p.s. Aristos Queue, nice to see you here more often again. I guess you are less busy with your projects now :) Welcome back.

Tomi

Link to comment

QUOTE(Paul_at_Lowell @ Jul 18 2007, 02:36 PM)

*blink* Really??? They should be the same array if they're the same type... oh, wait... the type name. Crud. Yeah, that would skew the result. The data type includes the "name" of the wire in the output array.

Argh. I was trying to be helpful. Sorry for the red herring.

QUOTE(Tomi Maila @ Jul 18 2007, 03:43 PM)

p.s. Aristos Queue, nice to see you here more often again. I guess you are less busy with your projects now
:)
Welcome back.

I was on vacation. A much needed one.

QUOTE

I'd really like to see LabVIEW to automatically add the available methods for particular class to the context menu of a class wire. AQ, are we seeing this anytime soon?

No. There have been so many usability challenges raised to this idea. I like the idea, and a couple of members of my team have tackled it, but it ends up being unpleasant. Basically, recall the complaints that occur when LV moves the palettes around between versions of LV. Now imagine if the palettes changed around every time you edited your class. The grumbling gets loud. Then there's the constant debate about *which* menu should appear first -- if you popup on a child wire, should you get a single palette with all the methods of child and parent and grand parent? Or should these be separate palettes? Should the parent be on a subpalette or should the child be on a subpalette?

All in all, I've decided it is low priority -- if you're creating a class to be reused, when you're done with development you can create a palette by hand and set it to appear in the context menus (using the class' property pages). If you're still developing the class, just use the project tree as the palette -- it's close at hand generally.

Link to comment

QUOTE(Aristos Queue @ Jul 19 2007, 12:35 AM)

All in all, I've decided it is low priority -- if you're creating a class to be reused, when you're done with development you can create a palette by hand and set it to appear in the context menus (using the class' property pages). If you're still developing the class, just use the project tree as the palette -- it's close at hand generally.

I've understood that all ancestor classes need to be in the project explorer during the development of any decendent class. I may have misunderstood. Am I wrong here?

Link to comment

QUOTE(Tomi Maila @ Jul 19 2007, 08:10 AM)

I've understood that all ancestor classes need to be in the project explorer during the development of any decendent class.

Hi Tomi

You don't need to have the base class in the project explorer, but it will be loaded into memory anyway since it's refered to.

And ofcause all base-class members.

The build in function: "MySubClass->New->Override VI" still works, but the GDS-toolkits, "MySubClass->GOOP->Add Method..." don't find which override methods that are possible to create.

I might fix this in the next version of GDS, which will be relased after NI-week.

//Mikael

Link to comment

Gavin and Tomi,

Your (similar) solutions look like just what I was seeking. Thanks! :thumbup:

In particular, using the variant input means I can write a general search method rather than a custom method for each class (which I had to do--well, or else copy a large code snippet) with the downcast check method.

Anyway, I wrote a class-specific search 1D array method. I'm still testing it, but so far so good. I need to look closer at the parsing of the type string and data string you did, Gavin, to make sure I understand it.

Link to comment

QUOTE(Gavin Burnell @ Jul 18 2007, 01:28 PM)

I've edited my original post with a new version of my class namer tool that extracts more information from the class reference and (I think) now includes enough to properly test the class identity.

My search algorithm works fine now but there is the minor issue--well, minor for my purposes--that one can wire pretty much anything to it (although Gavin's code will filter this at run-time) since I left the input as variant (and array of variant). Is there a "LabVIEW object" type that I can use here? Hmmm....Gavin, I see you have an object called "LV Class In" on your diagram. Is this a specific class or did you find a generic class? If so, where did you get it? I don't see such a thing....

Link to comment

QUOTE(Paul_at_Lowell @ Jul 19 2007, 05:01 PM)

My search algorithm works fine now but there is the minor issue--well, minor for my purposes--that one can wire pretty much anything to it (although Gavin's code will filter this at run-time) since I left the input as variant (and array of variant). Is there a "LabVIEW object" type that I can use here? Hmmm....Gavin, I see you have an object called "LV Class In" on your diagram. Is this a specific class or did you find a generic class? If so, where did you get it? I don't see such a thing....

Yes, you can have a Labview Object control, the reason I used a variant was to do with how the coercion works and the need to get a application instance ID.

The application instance ID is only in the type descriptor array not in the flattened string data. Now, if you make that input a LabVIEW Object control, then when you wire up your class control it will be cast to a LabVIEW Object first. Then you flatten that to a string, and recover the 'real' class name from the flattened string, but the type descriptor array refers to the wire type which is a LabVIEW Object and not a wire of your specific class. The problem is that the application instance (which is derived from the type descriptor array) for a LabVIEW Object is always FF FF. Therefore, although you get the correct class name you don't get the correct application instance id.

With the variant input, your 'real' class type is wrapped up in the variant, so when you flatten that to a string with a type descriptor array (using the flatten variant function) you get the type descriptor of your 'real' class with the real application instance id. The flip side is that you need to check that you are really looking at a Class and not at anything else which is why I have that little bit of error checking code first.

The best solution would be to wrap the class name finder up in an XNode which could do the check to make sure it was being fed a class at edit time, but I thought that was probably complicating matters a bit too much for a quick and dirty hacked solution. If I get keen I'll write the XNode and release it via the code repository (if nobody else does it first).

Oh and the random LabVIEW Object constant on my block diagram was a left over from a previous iteration of the code :rolleyes:

Link to comment

OK, well, I tried to put all this together. I attached a solution (not fully tested for all cases). I created this within a class library but you can remove the "ArrayOfObject in/out" without harm. I added some comments to Gavin's underlying code (which is the important part) so that with luck maybe even someone like me can understand it. :)

Link to comment

QUOTE(Paul_at_Lowell @ Jul 19 2007, 06:17 PM)

OK, well, I tried to put all this together. I attached a solution (not fully tested for all cases). I created this within a class library but you can remove the "ArrayOfObject in/out" without harm. I added some comments to Gavin's underlying code (which is the important part) so that with luck maybe even someone like me can understand it. :)

Uhhh, doesn't the application instance id always end up being set to the FF FF FF FF special value in your version ?

Commenting code is a good thing, I probably should do more of it... :)

Link to comment

QUOTE(Gavin Burnell @ Jul 19 2007, 10:35 AM)

Uhhh, doesn't the application instance id always end up being set to the FF FF FF FF special value in your version ?

Oh, I see! The type is always "LabVIEW Object." I missed that. You described that in a previous post... Returning to variants would solve this but leave the wiring probem.... XNodes, huh? I'm not sure what to do about this one....

Link to comment

QUOTE(Tomi Maila @ Jul 18 2007, 05:10 PM)

The ancestor classes do have to be found on disk, but they do not have to be added to the project tree. The ancestors will show up under Dependencies.

QUOTE(Gavin Burnell @ Jul 19 2007, 11:28 AM)

The application instance ID is only in the type descriptor array not in the flattened string data. Now, if you make that input a LabVIEW Object control, then when you wire up your class control it will be cast to a LabVIEW Object first. Then you flatten that to a string, and recover the 'real' class name from the flattened string, but the type descriptor array refers to the wire type which is a LabVIEW Object and not a wire of your specific class.

The next version of LV will have a VI in vi.lib to deal with this to let you get the actual type.

For the moment I'm not really coming up with any helpful solutions.

QUOTE(Paul_at_Lowell @ Jul 19 2007, 01:12 PM)

AH. Here we go... The attached VI will give you the name of the class ON the wire, as opposed to the name of the class OF the wire.

http://forums.lavag.org/index.php?act=attach&type=post&id=6422''>http://forums.lavag.org/index.php?act=attach&type=post&id=6422'>http://forums.lavag.org/index.php?act=attach&type=post&id=6422

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.