MikaelH Posted July 18, 2010 Report Share Posted July 18, 2010 Hi I get this annoying class error when I try to place a class in its own class private data. The private data control defines the default value for a class. This private data control has values set as the defaults that are illegal. Illegal default values include: any value of this class itself, any value of any child class, any class that has not been loaded into memory, and any class that uses this class as a member in its own private data control. If you do not see the problem value immediately, you might check the default value of any variant controls in the private data to make sure their default values are not the problem. If I understand this right, the default value of the Class Private Data Cluster saved in this class is illegal. So how do I change it and how did I get it illegal in the first place. A.zip Cheers, Mikael Quote Link to comment
Francois Normandin Posted July 18, 2010 Report Share Posted July 18, 2010 Illegal default values include: any value of this class itself. Hi Mikael, Take a look at Tomi Maila's presentation on recursion with classes. To achieve what you want, he uses a LabVIEW Object in his List.lvclass and takes care of the typecast in the methods. If you put A.lvclass as a member of A directly, that's illegal... but put a Generic Object in your A.lvclass and you're good to go. 1 Quote Link to comment
Daklu Posted July 18, 2010 Report Share Posted July 18, 2010 To achieve what you want, he uses a LabVIEW Object in his List.lvclass and takes care of the typecast in the methods. That's what I do as well. It works very well. Quote Link to comment
Jarrod S Posted July 18, 2010 Report Share Posted July 18, 2010 Hi Mikael, Take a look at Tomi Maila's presentation on recursion with classes. To achieve what you want, he uses a LabVIEW Object in his List.lvclass and takes care of the typecast in the methods. If you put A.lvclass as a member of A directly, that's illegal... but put a Generic Object in your A.lvclass and you're good to go. This is true. However, you don't have to use a generic Object. You can store any ancestor of an object in its private class data. So if there is some parent class that closely resembles the child class, it might be more useful to use that instead of an Object. But either will work fine. Quote Link to comment
MikaelH Posted July 19, 2010 Author Report Share Posted July 19, 2010 Thanks guys. One question remains though why aren’t we allow to do this? So for some reason LV doesn’t like us to be able to implement the Composition design pattern. I use this in my UML modeler where all my graphical objects on the diagram inherit from a Node base class. This class have 2 attributes, - One is a Parent NodeRef, since a object can have a parent node that owns this object. - And several ChildrenNodeRefs, that indicated which children objects this node has if any. So to get this working on our new GOOP4 DVR template we had to type cast the DVR reference into a U32 and place that in our Cluster of class private data. This works fine, the question is should it work or not? Why doesn’t LV allow me to do this straight away? Here’s our class template showing that this works just fine. A_class.zip Cheers, Mikael Quote Link to comment
Daklu Posted July 19, 2010 Report Share Posted July 19, 2010 One question remains though why aren’t we allow to do this? Suppose you had class S with an I32 and an instance of itself. What would happen when you dropped an object constant on the block diagram? Memory would be allocated for the I32 and for another instance S, which has its own I32 and another instance of S, which has its own I32 and another instance of S, etc. You'll fill all the available memory with instances of S. Using LVObject (or some other parent class) breaks the recursion in the class definition. So for some reason LV doesn’t like us to be able to implement the Composition design pattern. Not true. You can implement the composition pattern. It is perfectly legal for an object to contain instances of itself at runtime. You just can't define a class with a self-reference. Use LVObject as a container and do the downcasting as part of the accessor methods. I'd have to look more closely at the rest of your post before answering the other questions. No time right now... Quote Link to comment
Aristos Queue Posted July 19, 2010 Report Share Posted July 19, 2010 One question remains though why aren’t we allow to do this? There are four "interesting" cases of a class containing itself in its private data cluster. The cluster could contain... ... the class cube directly [this is functionally identical to the class cube inside a nested cluster] ... the parent class cube directly with the default value set to an instance of the child class ... the class cube in an array ... the class cube in a refnum (DVR, Queue, Notifier, Datalog, User Event, User Event Registration) If we're talking about direct inclusion (case #1), Daklu got the answer right in his post above. The same infinite allocation that he describes would happen in use case #2. So cases 1 & 2 are off the table permanently as "logically impossible to ever implement" (unless LV ever introduced a lazy evaluation language syntax which would be a very different programming model than anything that exists today -- I mention the possibility only so that someone doesn't say something like, "If it is impossible, how does Lisp or Haskell do it?") For case #3, if the array is non-empty, you have the same problem as 1 & 2, but if the default value of the array is empty, it would be fine. Case 4 never has to allocate the actual data of the class (it just allocates space for a reference cookie, a cookie whose default value is always Not A Refnum), so it should work. That, I think, is the heart of Mikael's question: Why doesn't this work in LabVIEW? What we found is that we could get some significant performance boosts during load, notably dynamic loading into an already running hierarchy, if a class hierarchy has no circular dependencies (meaning it does not reference itself, including indirectly). There's a lot of work to identify which class can instantiate and reserve first. If all the references are changed out for parent class references, users can still write all the functionality (albeit with a slightly modified syntax than they would generally try first) and LV could simplify the load and reserve algorithm considerably. I looked through various lists of recursive data structures. The most common that I saw were composition patterns, such as is in the Graphics shipping example in LV, where Collection inherits from Graphic and includes an array of Graphic. Those are unchanged because they are already including their parents, not themselves. The other class was the linked lists, trees, and graphs. Honestly, I expected most of these to be written once by someone who was an expert in LVOOP and then most users would just use them as libraries. That expectation was predicated on other features of LabVIEW existing which have not come to fruition. Even so, it appears (based on AE reports and my looking at user code when I get a chance to visit customers) that very few LV users ever attempt to build anything recursive, much less a recursive data structure, so I wager most of those who attempt it are people who are power LV users who generally know about LAVA and will post questions (like Mikael's) and find these answers. Not true. You can implement the composition pattern. It is perfectly legal for an object to contain instances of itself at runtime. You just can't define a class with a self-reference. Use LVObject as a container and do the downcasting as part of the accessor methods. Even better, define a parent class that is not recursive with dynamic dispatch methods for anything that would be recursive, then define a child class that overrides all the necessary VIs. That way you avoid the downcast. As of LV 2010, dyn dispatch is faster than downcast (although the compiler team is working on some new optimizations for future LV versions that may change the balance of power here).The <labview>\examples\LVOOP\Graphics\Graphics.lvproj has an example of the composition pattern. 1 Quote Link to comment
Daklu Posted July 19, 2010 Report Share Posted July 19, 2010 ...albeit with a slightly modified syntax than they would generally try first... Interesting comment. I take it R&D and Usability spend a lot of time trying to get things to work using syntax a novice user is likely to try? (This is one of those dev team considerations that I, as an end user, don't fully appreciate when I'm griping about Labview.) Even better, define a parent class that is not recursive with dynamic dispatch methods for anything that would be recursive, then define a child class that overrides all the necessary VIs. That way you avoid the downcast. As of LV 2010, dyn dispatch is faster than downcast (although the compiler team is working on some new optimizations for future LV versions that may change the balance of power here). Roughly how much faster are we talking about? This is one of those optimizations I probably wouldn't bother implementing unless the design called for a parent class anyway or I was looking for performance gains. Of course, by the time I run into an app where I'll need that performance gain I'll have completely forgotten about this trick. Someday I'll need to put together a list of optimizations... The <labview>\examples\LVOOP\Graphics\Graphics.lvproj has an example of the composition pattern. Huh. My first reaction was, "That's an interesting way to use a collection." In my code collections are separate entities with their own hierarchy and having a collection inherit from the Graphic class seemed odd. I went back and referenced GOF and realized the example's Collection class is the same as GOF's Picture class. Graphics.lvproj implements GOF's example almost exactly. Nice! Now it just needs to be tagged with a "composition" keyword. Quote Link to comment
MikaelH Posted July 19, 2010 Author Report Share Posted July 19, 2010 Suppose you had class S with an I32 and an instance of itself. What would happen when you dropped an object constant on the block diagram? Memory would be allocated for the I32 and for another instance S, which has its own I32 and another instance of S, which has its own I32 and another instance of S, etc. I can see that this would happen in a "By Value" world, but not in a "By Reference" world, because the pointer to the same class would be NULL at the start and would not causing any recursive memory allocation problem. Of cause LabVIEW is by value, but if I had to develop the source code for LabVIEW, internally I would use pointers for memory allocation and just let the user (me and all other LabVIEW fans), get the feeling of a by value flow development language. Of cause I don’t have all knowledge of how to write a such sophisticating and great development language as LabVIEW so I’m sure I don’t understand all hurdles and problem it causes to have a Class Cube in its own private data cluster. You can implement the composition pattern. It is perfectly legal for an object to contain instances of itself at runtime. You just can't define a class with a self-reference. Use LVObject as a container and do the downcasting as part of the accessor methods. Yes you are right; we can implement all design patterns in the GOF with a little tweaking here and there, But it would be nice to be able to implement these with less tweaking, I think/hope that in a future version of LabVIEW, we'll both have support for interface and and Call by Reference node with dynamic dispatch class member VIs. //Mikael Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.