Jump to content

Ideas for an IsSibling algorithm?


Recommended Posts

I have the following class structure:

- Grandparent

-- ParentA

--- ChildA1

--- ChildA2

--- Child...

-- ParentB

--- ChildB1

--- ChildB2

--- Child...

-- Parent...

I am creating an array of Child objects at runtime; however, before adding a Child to the array I want to make sure it does not have any siblings already in the array. In other words, if I'm trying to add ChildB1 to the array, I want to raise an error if ChildB2, ChildB3, etc. are already there.

Given that the parent classes are unknown at design-time and not directly available at run-time, is there a way to compare two objects to see if they derive from a common parent? The Grandparent is known at design-time and can be used. I can think of solutions by adding framework methods to the class hierarchy, such as an abstract GetParent method in the Grandparent class. I'd like to do it using LV prims to avoid cluttering up the hierarchy. I don't think this is possible given the constraints, but I thought I'd throw it out there for the experts to chew on.

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

This is releated to the Interface Framework. The other day I stumbled upon 'Preserve Run-Time Class Demo' in the Example Finder and realized I could eliminate the downcast after getting an Interface in my Baby Demo.

post-7603-125489228478_thumb.png

Also, using type information instead of "Name" value to retrieve a specific Interface eliminates the problem of different Interfaces having the same name.

Link to comment

Be patient I am trying to learn LVOOP.

Fro a set of plug-in classes the Init methods append their class name to an attribute of the of the top level class called "Type". The children all let their parents init run first so I end up with a name that is constructed based on the inheritance. Since access to that method is public, user of the class can determine the hiarchy of the classes found.

Example Type

PlugIn_Serial_Anemometer_3Axis

PlugIn_Serial_Anemometer_2Axis

PlugIn_DAQ_AI

by stripping of the text following the final underscore, I can see the frist two are siblings while the third is not.

Really trying hard to help,

Ben

Link to comment

Be patient I am trying to learn LVOOP.

No worries, we all are. smile.gif

PlugIn_Serial_Anemometer_3Axis

PlugIn_Serial_Anemometer_2Axis

PlugIn_DAQ_AI

by stripping of the text following the final underscore, I can see the frist two are siblings while the third is not.

A string-based tag works if you have control over the entire hierarchy. In my case I don't. Users can create their own Parent classes and give them whatever name they want. In your example perhaps your Serial Anemometer class is from manufacturer A, but I create a Serial Anemometer class for devices from manufacturer B. My plug-ins and your plug-ins will be tested as siblings, even though they are not. (Besides, I hate Init methods. wink.gif )

Link to comment

... (Besides, I hate Init methods. wink.gif )

The Book by Craig larman (?) on UML and patterns is often referencing the creation (I still cal them Init) of objects and GRASP includes the "Creator" design pattern to aid in deciding who is invoking the Creation method. Is this expressed "hatred" a semantic issue (you don't like the word "Init") or the whole idea of a "Create" method something that has fructarted you?

As it stand now I have accepted them (Create methods) as being part of the game and have been thinking about how to exploit them rather tahn avoid them.

Like I said, I'm just trying to learn something.

Thank you!

Ben

Link to comment

Is this expressed "hatred" a semantic issue (you don't like the word "Init") or the whole idea of a "Create" method something that has fructarted you?

"Fructarted?" :D That's my new favorite word!

Neither really. The idea of a Create method doesn't bother me, but the requirement of using a Create or Init method on an object constant that looks like it should work fine without one does bother me. More details can be found here.

Link to comment

You can resolve this issue using property nodes Application:All VIs In Memory or maybe also Application:All Libraries in Application Instance together with Preserve Run-Time Class primitive to resolve the class hierarchy in memory.

The solution goes as follows. For each class or class private data control VI in memory, load the class default value. That can be loaded with Get LV Class Default value VI and also if I remember correctly, some scripting node returns it. Then construct a hierarchy tree of the classes in memory using Preserve Runtime Type primitive. This needs to be done only once unless you dynamically load classes during the runtime. Once you have the class hierarchy, your sibling test is trivial.

Tomi

Link to comment

Neither really. The idea of a Create method doesn't bother me, but the requirement of using a Create or Init method on an object constant that looks like it should work fine without one does bother me. More details can be found here.

To prevent this confusion I never use the object constant on the BD to 'create' objects.. Basically all objects are created by explicitly placing the constructor method on the BD. I should note I use by-ref classes for the major part of my designs and they come naturally with a create method for construction, but for by-value classes I use the same paradigm. The constructor typically has no input terminal for the class wire.

For most LV users using a create-destroy paradigm is quite natural since there's a lof of that already in LV (instrument I/O, file I/O, Queues, etc..).

Link to comment

To prevent this confusion I never use the object constant on the BD to 'create' objects.. Basically all objects are created by explicitly placing the constructor method on the BD. I should note I use by-ref classes for the major part of my designs and they come naturally with a create method for construction, but for by-value classes I use the same paradigm. The constructor typically has no input terminal for the class wire.

For most LV users using a create-destroy paradigm is quite natural since there's a lof of that already in LV (instrument I/O, file I/O, Queues, etc..).

What about reuse for the constructor* method? I find I regularly use dynamic dispatching (which requires input/output) in case the child method needs to call the parent on override or just needs to use it anyway.

*This means it's not a true constructor (the LVOOP constant on the BD is really), and I even have to set some data before it sometimes, so it is really better suited to the term initialiser, but I prefer constructor.

Then I have the problems above - that I can't force the constructor to be used (i.e. I might forget to use it in all cases!!)

Trying to learn something too...

I would love to be able to force a constructor/initialiser or something similar.

Link to comment

You can resolve this issue using property nodes Application:All VIs In Memory or maybe also Application:All Libraries in Application Instance together with Preserve Run-Time Class primitive to resolve the class hierarchy in memory.

The solution goes as follows. For each class or class private data control VI in memory, load the class default value. That can be loaded with Get LV Class Default value VI and also if I remember correctly, some scripting node returns it. Then construct a hierarchy tree of the classes in memory using Preserve Runtime Type primitive. This needs to be done only once unless you dynamically load classes during the runtime. Once you have the class hierarchy, your sibling test is trivial.

Tomi

Thanks Tomi! I'll have to play around with that and see how well it works in my situation.

The Create method discussion continues here.

Link to comment

What about reuse for the constructor* method? I find I regularly use dynamic dispatching (which requires input/output) in case the child method needs to call the parent on override or just needs to use it anyway.

*This means it's not a true constructor (the LVOOP constant on the BD is really), and I even have to set some data before it sometimes, so it is really better suited to the term initialiser, but I prefer constructor.

Then I have the problems above - that I can't force the constructor to be used (i.e. I might forget to use it in all cases!!)

You're right.. You need class wire input on the constructor for the childs to be able to call the parent's constructor. I should have said I just never connect the object constant to the constructor method, simply leave the class input terminal unwired.

I would love to be able to force a constructor/initialiser or something similar.

I don't really mis the ability to be able to force it, but I agree it would be nice if it was possible. I wouldn't want the code to be run as part of the cube-constant though, it wouldn't feel natural.

Link to comment

Cheers for the reply, I like to know what others are doing :)

You're right.. You need class wire input on the constructor for the childs to be able to call the parent's constructor. I should have said I just never connect the object constant to the constructor method, simply leave the class input terminal unwired.

But if I use dynamic dispatching, the input is required, and I have to wire an object in - is there a way around this?

Link to comment

But if I use dynamic dispatching, the input is required, and I have to wire an object in - is there a way around this?

I believe the work around it to use a factory method.

A factory method would be a vi not in the class that passes out an object based on string or enum input. The user will have to downcast to the specific object requested to use any methods not exposed by the common parent. If you have complete control over the entire class tree you can include the factory method when distributing the class without too much trouble. If you expect users to extend your class tree, they'll have to create their own factory method that wraps yours and add their classes to it. Obviously they'll need to rename their factory method, or wrap it in a library, or wrap yours in a library.

Link to comment

Dak,

Back to your original question of finding common lineage...

I do not know how to programmatically traverse a class hierarchy given an instance of an object, expect to make the object do it. So, would it be feasible to make a 'must override, must invoke parent method' method that returns an array of strings (class names), or even an array of objects that are essentiall empty (DVR not allocated) instantiations of classes.

At that point you have the entire inheritance tree for both objects and a level by level comparison can be done.

By the way, the class factory idea does work well. In my case I previously write a LV XML file of an array that contains every class that I expect the Factory to create. In my application where I use the class factory I have it read the file. I suppose I could tell the factory to read multiple XML files and therefore add to its list (extending it's capabilities). All classes must implement the DD Create method as it will be called when you use ClassFactory.CreateNewInstance. There are probably other ways to implement the array without actually resorting to a file. Your array of implemented classes comes to mind from your interface framework.

-kugr

Link to comment

You're right.. You need class wire input on the constructor for the childs to be able to call the parent's constructor. I should have said I just never connect the object constant to the constructor method, simply leave the class input terminal unwired.

But if I use dynamic dispatching, the input is required, and I have to wire an object in - is there a way around this?

Honestly guys, why the heck do you want to use dynamic dispatching for create/constructor methods. The only reason to use dynamic dispatching is that you wire something into a method and you don't know what exactly is that something. And therefore you let the method to be chose at runtime. When you create an object, you always know what you want to create, at least you should. If you don't know what you are creating, then you should use a factory pattern or similar. But I think constructors should always be static methods and call static parent constructors.

So if you have a class My Class, create method should be called Create My Class and it should be static dispatched. It should have class input terminal only for a single reason, so that child constructor can call it. I myself usually make the class type in terminal even optional, to make clear that is should not be used in anywhere else but when child constructor is calling the method.

Tomi

Link to comment

Honestly guys, why the heck do you want to use dynamic dispatching for create/constructor methods. The only reason to use dynamic dispatching is that you wire something into a method and you don't know what exactly is that something. And therefore you let the method to be chose at runtime. When you create an object, you always know what you want to create, at least you should. If you don't know what you are creating, then you should use a factory pattern or similar. But I think constructors should always be static methods and call static parent constructors.

*This means it's not a true constructor (the LVOOP constant on the BD is really), and I even have to set some data before it sometimes, so it is really better suited to the term initialiser, but I prefer constructor.

Thanks for posting. I get what you are saying, and I guess my terminology sucks, or is confusing at least. But as I stated above its not really a constructor, its an initialiser. This is just something I did when trying to learn LVOOP. It's not easy/neat to construct an object that requires a lot of data. I end up having to use set methods then run the initialiser. By default I have always left this as Dynamic Dispatching, as I have found somethimes I want to override the behaviour of the initialiser for child objects. Is this wrong?

So if you have a class My Class, create method should be called Create My Class and it should be static dispatched. It should have class input terminal only for a single reason, so that child constructor can call it. I myself usually make the class type in terminal even optional, to make clear that is should not be used in anywhere else but when child constructor is calling the method.

I do not understand this, are you able to please clarify - if you wire in, or don't wire in a child object, won't your constructor still pass out the parent object regardless? If that is the constant on the block digram wire to the output terminal. Or is there something else going on under the hood I am missing?

Cheers

Link to comment

Thanks for posting. I get what you are saying, and I guess my terminology sucks, or is confusing at least. But as I stated above its not really a constructor, its an initialiser. This is just something I did when trying to learn LVOOP. It's not easy/neat to construct an object that requires a lot of data. I end up having to use set methods then run the initialiser. By default I have always left this as Dynamic Dispatching, as I have found somethimes I want to override the behaviour of the initialiser for child objects. Is this wrong?

No, not really because using dynamic dispatch initializer allows you to outsource the task of initializing a set of different classes of objects to some other method. For example you could have different kinds of binary streams such as binary file stream or network binary stream. Setting up binary stream parameters can be separated from the actual opening of the binary stream You can for example specify the file path to use for the file binary stream or specify the network address to use for the network binary stream. Then you can pass either of the stream specifications to a method that actually opens the stream using dynamic dispatch open method. I think this is kind of an initialization phase for the streams. And the open method can even take parameters such as input vs. output stream.

I do not understand this, are you able to please clarify - if you wire in, or don't wire in a child object, won't your constructor still pass out the parent object regardless? If that is the constant on the block digram wire to the output terminal. Or is there something else going on under the hood I am missing?

My constructors look most of the time like this.

post-4014-125525129148_thumb.png

The terminals on the left are for construction parameters. In the example case there is only one, the States terminal. The terminal on the right returns the constructed object. The terminal on the top (right) is an optional terminal for the child object. It should not be used unless the constructor is called from within child constructor. It should always be used within child constructor. When you pass in a child object to the parent constructor, the parent constructor naturally returns the same object type that you pass in. Or it should. It returns the child type object, if your class in input terminal is fully connected (see glossary below) to the class out output terminal. There may be unbudnle/bundle nodes and other fully connected class methods on the route of the wire. However you cannot have things like class constant wired to the output terminal on any possible route.

An image should tell more than 1000 words. An example of a valid fully connected class method is below. You can test if your class method is fully connected by making both class in and class out terminals dynamic dispatch. If the VI gets broken, then it is not directly connected. Only directly connected VIs can have dynamic dispatch input and output.

post-4014-125525197777_thumb.png

Glossary

Fully connected: All of the data paths that lead to the class output terminal must originate at the class input terminal. If there are subVIs on any of the routes, the the subVIs must also be fully connected. All methods with dynamic dispatch input and dynamic dispatch output are always fully connected.

Link to comment

So, would it be feasible to make a 'must override, must invoke parent method' method that returns an array of strings (class names), or even an array of objects that are essentiall empty (DVR not allocated) instantiations of classes. At that point you have the entire inheritance tree for both objects and a level by level comparison can be done.

That's a more generalized solution -- and more complex -- than what I need. Really all I want to do is check and make sure an InterfaceBag doesn't contain two implementations for the same Interface. I'd prefer to do direct type-checking rather than relying on strings defined by the developer. Since this feature is a check for the interfaceable class designer, not the class user, I'm going to shelve this idea for now. Framework simplicity is more important at this point.

Your array of implemented classes comes to mind from your interface framework.

Funny you should mention that. I don't know if you've seen my latest update but in the demo I've changed the workings of the interfaceable object's GetInterfaces method. Rather than store the array as private data, I simply dynamically create a new array of concrete Interfaces every time the GetInterfaces method is called.

Honestly guys, why the heck do you want to use dynamic dispatching for create/constructor methods. The only reason to use dynamic dispatching is that you wire something into a method and you don't know what exactly is that something. And therefore you let the method to be chose at runtime. When you create an object, you always know what you want to create, at least you should. If you don't know what you are creating, then you should use a factory pattern or similar. But I think constructors should always be static methods and call static parent constructors.

So if you have a class My Class, create method should be called Create My Class and it should be static dispatched. It should have class input terminal only for a single reason, so that child constructor can call it. I myself usually make the class type in terminal even optional, to make clear that is should not be used in anywhere else but when child constructor is calling the method.

I commented on this here.

Link to comment

My constructors look most of the time like this.

Thanks Tomi and Daklu for replying to my questions.

Tomi thanks heaps for the latest post, there is nothing I :wub: more then seeing the insides of a programmers brain - i.e. their code. And Daklu, no intential thread hijacking on my side - sorry mate! :beer_mug:

Link to comment
  • 2 weeks later...

Fully connected: All of the data paths that lead to the class output terminal must originate at the class input terminal. If there are subVIs on any of the routes, the the subVIs must also be fully connected. All methods with dynamic dispatch input and dynamic dispatch output are always fully connected.

Is there official NI terminology for the concept I called fully connected? What do you think should be the best term for the concept? Somehow it resembles mathematical concept of connected manifolds. Maybe reverse or inverse connected could be more clear. They somehow tell that input need not always terminate to output terminal but instead output terminal must always originate from input terminal.

Link to comment

Is there official NI terminology for the concept I called fully connected? What do you think should be the best term for the concept? Somehow it resembles mathematical concept of connected manifolds. Maybe reverse or inverse connected could be more clear. They somehow tell that input need not always terminate to output terminal but instead output terminal must always originate from input terminal.

I can't say it has an official name but that wire pattern over-laps with the rules for working in-place. This thread on the Dark-side

http://forums.ni.com/ni/board/message?board.id=170&view=by_date_ascending&message.id=191864#M191864

includes posts by Greg McKaskle exaplaining how we can construct our diagrams such that sub-VI can work in the buffers of their callers. I have reviewed LVOOP code using that tidbit and LVOOP seems to be 100% consistant with that idea.

Ben

Link to comment

Is there official NI terminology for the concept I called fully connected? What do you think should be the best term for the concept? Somehow it resembles mathematical concept of connected manifolds. Maybe reverse or inverse connected could be more clear. They somehow tell that input need not always terminate to output terminal but instead output terminal must always originate from input terminal.

I can't say it has an official name but that wire pattern over-laps with the rules for working in-place. This thread on the Dark-side

Inplaceness is a competely parallel orthogonal concept. It is a compile time optimization technique used by LabVIEW to reuse buffers. The concept of inverse fully connected wires is about type propagation, if runtime output type can be guaranteed to be a function of runtime input type(s), irregardless how the VI is executed.

Link to comment
Is there official NI terminology for the concept I called fully connected? What do you think should be the best term for the concept? Somehow it resembles mathematical concept of connected manifolds. Maybe reverse or inverse connected could be more clear. They somehow tell that input need not always terminate to output terminal but instead output terminal must always originate from input terminal.
Well, I have a term for this that I use in the code. I've never had a need to expose users to that term. In general, as in the Error List Window, we talk about run-time type propagation, as in, "The run-time type must be propagated from dyn input to dyn output." We also use "run-time type preservation," which is how the new LV 2009 primitive "Preserve Run-Time Class" got its name. In the code, I call these two terminals "thralled", since the result of the successful propagation is that the output terminal's type is now thralled to the input terminal's type. I picked this somewhat arcane term because it was unique in the LV vernacular, whereas "linked" or "chained" or "bound" had other uses. If you'd like to use that term, I can guarantee that nothing else in LV uses that term, either in the code or in public.
Inplaceness is a competely parallel orthogonal concept. It is a compile time optimization technique used by LabVIEW to reuse buffers. The concept of inverse fully connected wires is about type propagation, if runtime output type can be guaranteed to be a function of runtime input type(s), irregardless how the VI is executed.
To restate this using my terminology... "If the input terminal is successfully propagated to the output terminal then the output terminal is thralled to the input terminal. Given this guarantee, when a subVI is written to take a parent class but the subVI node's input terminal is wired with a child class, automatic downcasting can convert the output terminal to match the input terminal."
  • Like 1
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.