Jump to content

K-node

Members
  • Posts

    90
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by K-node

  1. I nosed around this for a little bit and I like it. Nice work.

    I would prefer, as a developer using this framework, not to have to have the ImplementationCollection as part of my class. I would prefer this on the Interfaceable class. I realize that you would need to change the Interface class to store a more general (but common) base class as the Target ObjRef. You could use the LabVIEW Object or create a new common base class.

    How does the ImplementationCollection get populated? I am restricted by business rules on what I can install on my laptop, so the OpenG stuff was out of the question. I replaced the references to this using a string array for the keys and an Interfaceable object array for the items. But the list is empty when I finally try to get the named interface in the BabyDemo vi. Not sure what I broke. Perhaps you can help there. In the mean time I simply added the ISleepableBaby object to the ImplementationCollection of Baby in the _GetInterfaces method I had to override.

    I kinda like your _CreateDVR method. As I get more and more properties I might find it a pain and would prefer to resort to a Create method that is called once - but then from the User perspective it is one less thing to remember to call as the User instantiates these things.

    Is there a reason that the Interface Class holds a DVR to its target and not just an Interfaceable object as the target?

    I will probably have more thoughts, but overall, well done. Thanks for sharing this with us.

  2. So why don't we simply automate the creation of the dynamic dispatch methods corresponding dynamic dispatch by-value method by scripting. Say you could have a virtual folder in your class and a scripting tool that would automatically synchronize the folder content so that it would create a corresponding DVR method for each non-override dynamic dispatch method in the folder.

    Tomi

    If I am understanding your approach, the script would essentially automate the creation of wrappers. Interesting.

    What would you do with the override dynamic dispatch methods in the folder? Handled at the parent's virtual folder?

    So, would my main vi wire up the method that has a DVR terminal?

  3. I am using LV2009 and FP:State property toggles between Standard (in subpanel) and Closed (not in subpanel)- but not maximized ??

    That is ok tho, cause now I have a way for the VI to test itself.

    Cheers

    Can I have multiple subpanels (on the same 'main' vi) show the same opened vi? Each representing its own instance (and access to its own data)?

    Say forinstance that I have a VI that shows a word from a list. I have three lists - one each for subject, verb and object. I know how to set the value of a front panel item, so I can set a VI's data in that respect. I just cannot seem to InsertVI into multiple subpanels.

    Any suggestions?

  4. Sorry, this kind of duplicates what Jim just said.

    So you would always, when using DVRs, place a semaphore to the class on the top of the hierarchy and when ever accessing any data in the hierarchy you would lock the whole hierarchy using semaphore?

    I think that Jim would consider only implementing the lock-unlock on an as needed basis. I am not sure that all transactions can be generalized as atomic. The approach of the class as a DVR or always using a semaphore for data access clearly serializes access to the class which defeats the parallel nature. Sure this will protect the programmer from potential pitfalls of non-synchronized access, but it can also bottle neck other threads.

    'Atomic' transactions are not just limited to intra-class operations. What about an accounting system where assets have to equal liabilities. Adding an asset then has to have a comparable increase in liability. If I were to implement an OO hierarchy on an accounting system, assets and liabilities would not be one class, but I would need to be able to 'freeze' access to the system while a transaction is completed. In those cases I would probably have some 'token' that I can grab from the accounting system and return when my transaction was done.

    I would implement the same approach for intra-class transactions. This could get pretty complicated as some transactions are independent (multiple transactions and on semaphore) and others are interleaved (one transaction multiple semaphores - if that is possible). Or I can make my life simple and have only one semaphore for the entire class - invoking as needed.

    If LV2009 supported some form of dynamic dispatch on a DVR, I do not think we would be having this discussion. It would probably be the opposite - how do I let other threads have asynchronous access to other (read only) methods in my DVR'd class hierarchy.

    I choose to go to the DVR'd data member route because the programming overhead (time and complexity) to implement a framework that uses class DVRs that supported dynamic dispatch was not appealing. And dynamic dispatch was more important to me than protecting myself from the complexities of multi-threaded programming.

    • Like 1
  5. x

    I guess my observation is that the behavior of the vi added to the subpanel is different based on it location in the LabVIEW Project hierarchy.

    I have attached a simple example to illustrate. I comes from the LV2009 example of subpanels. I added an unused class (TestTermination.lvclass) in the project soley for the purpose of having a 'folder' to drag the vi that is being used in the subpanel.

    To replicate:

    1) Run the Simple Subpanel.vi.

    2) Click the Abort Execution button (the red stop sign in the tool bar).

    3) Open up the plugin1.vi and note that it is not running.

    4) Move the plugin1.vi into the TestTermination 'folder' from LV's Project explorer window.

    5) Run Simple Subpanel.vi.

    6) Click the Abort Execution button (the red stop sign in the tool bar).

    7) Open up the plugin1.vi and note that it IS still running.

    8) Optionally create a virtual folder and move plugin1.vi into it. Run again, abort and open plugin1.vi to see that it too has stopped.

    I hope this helps to explain.

    The work around is to add an Invoke Method function and use the Abort VI method, ignoring the error in the event that it is not running.

    SubPanel.zip

  6. Not sure this is the right forum, but it is loosely related to labview classes.

    So, I created a vi that represented a 'view' of the object. And because it is part of the class (not dynamic dispatch), I have it under the class icon in the project explorer.

    On a 'main' vi I added a subpanel and wired the refnum of the 'view' vi to the subpanel. All good so far.

    I run the 'main' vi, but when I "Abort Execution", the 'view' vi, continues to run though no longer visible. (I can open it up from the project explorer window and the execution arrow indicates it is running).

    If I move the 'view' vi to somewhere NOT under a class icon of the project explorer window - top level under 'My Computer' or even a Virtual Folder - the 'view' vi will terminate automatically - which is what I want.

    It does not seem to mater where on the disk the file resides.

    This is probably a feature, but I would like to turn it off. Any ideas?

  7. Your tool makes me both happy and sad, both motivated and depressed.

    It is nice to see people using classes and using them so much that they write tools to extend them and make them more useful. It's just this particular tool... you see, this used to be in LabVIEW, but it never shipped. First I was told -- by multiple sources -- that using a text display was bad, that it needed to be the icon display or whatever the user had configured in their Tools>>Options for palette displays. Ok, so I made LV build an on-the-fly graphical palette. But then it was shot down because the layout was inconsistent: things in the palette shouldn't move when a new VI is added to the class, but adding new VIs at the end means nothing is ever findable. Can't you make it alphabetical but read my mind and not be alphabetical when I don't want them to be? Shouldn't virtual folders have something to do with it? Why aren't the parent methods folded in? Why are they in sub folders? Shouldn't they be in superfolders? What the heck is a superfolder? Perhaps the palettes should be named in iambic pentameter. Can you make all the icons rhyme?

    Clearly, no good deed goes unpunished.

  8. SciWare and I have the same first name (yes, with a K), so it was funny to read your first reply as if you were talking to me. I agree with you on all of your points. Your downside point #1 (not knowing if class's data is inside a DVR) is rather critical too. It is very dissapointing to use a class as if its data was inside a DVR and find out that it does not. My solution is to have all of my classes support this concept. I am not sure how painful this is going to be in the long run as my project is in the early stages. I am essentially a one man show on the LVOOP front at my company. My colleagues have lots of LV experience but little OOP. I came on board earlier this year with the oppposite. This forum has been a life saver!

    Anyway, this extra work is a nuisance and I would rather migrate to an NI implementation.

    Two more disadvantages of DVR's data members:

    1)DEBUGGING: With DVR'd data members, when you look at an object, all you see is the reference number. This is certainly true for DVR'd objects as well, but perhaps you would be in a IPE more often than just the Read/Write accessor methods.

    2)Flattten to XML: Here too all you get is the reference number of the data. Not surprising, just dissapointing.

    Even with these two additions, I am not swayed until NI comes out with something to help.

  9. Hi Kurt,

    I'm happy to hear you say this, since I've come to the same conclusion while talking it over with other members of my team. IMO, the value of being able to Dyamic Dispatch any method, regardless of whether it's a by value or by reference method, without having to create special, duplicate by reference wrapper methods around dynamic by value methods is huge.

    The only downsides (that I can see) of using the DVR inside an LVOOP object are:

    1) You can't tell just by looking an an object that it's by reference (as you can when you see a DVR with an LVOOP object inside)

    2) You have to unbundle the DVR before you can pass it into a IPE Structure

    Oh, and there's one situation that you also have to be very careful for:

    If you're inside a child method and you call a parent method inside an IPE structure, you might deadlock if the the parent method is itself, or calls inside of it, a dynamic dispatch method that results in child method being called.

    With this in mind, one feature that I'd love to see in LabVIEW is for IPE structures to be smart at run-time and output an error (rather than deadlock) if an IPE is called inside another IPE and tries to dereference data that has already been dereferenced by the outer IPE.

    Cheers!

    I see that you posted similar thoughts, just as I was typing up my reply to Kurt, above smile.gif

    Cool! It seems that we're all starting to converge on the preferred methodology (pun appreciated but not intended) for by ref OOP in LV2009.

    I guess that I would add that if NI were to implement either the ability to dynamic dispatch on methods with DVRs of objects OR the ability to wire a DVR of an object into a by value method (dereferencing/referencing behind the scenes) then I would probably migrate over to DVRs containing objects, rather than vice versa. But, until then...

    SciWare and I have the same first name (yes, with a K), so it was funny to read your first reply as if you were talking to me. I agree with you on all of your points. Your downside point #1 (not knowing if class's data is inside a DVR) is rather critical too. It is very dissapointing to use a class as if its data was inside a DVR and find out that it does not. My solution is to have all of my classes support this concept. I am not sure how painful this is going to be in the long run as my project is in the early stages. I am essentially a one man show on the LVOOP front at my company. My colleagues have lots of LV experience but little OOP. I came on board earlier this year with the oppposite. This forum has been a life saver!

    Anyway, this extra work is a nuisance and I would rather migrate to an NI implementation.

  10. I've been having another play with the concept of datamember DVR inside object ref and it’s appearing to be solid.

    The only thing you need to watch is that you don't perform a method call inside an In Place Structure DVR R/W that acts on the same data. So placing a method of the same class or a parent method with dynamic dispatch will cause it to lock. Placing a parent only method inside a child method's InPlace Structure DVR R/W is OK since it only acts on the parent data which has its own DVR. But in the end it’s the same kind of rules you would use as before when you had lock and unlock primitives in previous architectures.

    I haven’t been able to create a race condition as a result of implementing parent and child data member DVR’s. Since parent data is accessed in a child by parent methods the data is protected, the data locking protection mechanism exists at all levels of the object hierarchy.

    Thanks for the update. I too have seen the lockup. It can be not-so-obvious too. That is, you could call what appears to be a parent method that then calls a dynamic dispatch method that ends up attempting to access the same DVR you started in. Hope that was clear wacko.gif .

    All in all, I am finding this a very sweet way to implement objects as references yet still allow me to have dynamic dispatch work. I am still expecting to find a 'gotcha', but for now I am enjoying the feature.

    I have modified daklu's DVR Composition project such that it implements the member vars as a DVR of a cluster. The original DVR Composition project primarily showed an approach to facilitate Interfaces and Implementations by using DVR's of objects. The addition of DVR member variables eliminated the IPE structures from the general application code seen in Main.vi and reduced the casting that was used inside the IPE of the Multiply By Two Implementation. I hope to post this soon with some screen shots. My biggest problem is that my development machine is not on the network and my network machine is restricted to have only certain applications. So the transfer is just one more hurdle.

    Between your scheme of DVR'd member variables and daklu's Interface/Implementation work, this solved a huge problem I was having in my project. I also plan on posting some of this too. I am a bit restricted on what my employer will allow me to publish nono.gif .

  11. The short answer is no. I don't quite understand exactly what changes you made. If you can post images of your code it would help me understand your implementation. (My LV'09 trial license expired and I haven't got a home license from work yet.)

    I will work on that. I kind of destroyed it when I was playing with it further. I was trying different approaches to the structure. Should have left it alone while it was working.

    Danger, Will Robinson! Deep inheritance hierarchies aren't very malleable and you may find yourself unable to accomodate future changes. Or worse, you could end up hacking in modifications and ending up with very brittle code. Can you post a diagram of your object model?

    Perhaps deep is a relative term (there are only 5 levels). I will post a diagram soon. I need to grab Visio or something. I work for a huge company and it takes a bit longer to get through the red tape of allocating a license.

    Anyway, so far it has worked for me. I am using SciWare's approach regarding making the class's private data cluster contain a single DVR to a Strict TypeDef (I can also see advantages to multiple DVRs). I have hit some deadlock situations where IPEs have competed, but that was rather poor implementation on my part. I know I will hit more as I progress, but it seems better appraoch from a class usability standpoint. All of the IPEs are held inside the class's methods (typicaly data access methods). The calling VIs do not know anything about DVRs and DynamicDispatch works great. What is a real pain is debugging. Putting a probe on a wire that represents an object AND that object uses DVRs as member variables - all you see is the refnums! I am not surprised at this. I would like a way to dereference these values in the debugger. Am I missing something?

  12. I am developing something similar. For simplicity I added a string variable to the base object representing a name and also had the 'ObjectManager' keep a separate array of strings. So, I search for an object by name using the 1D array search function. The index found is used in the return the object from the ObjectManager's list.

    I am doing this in LV2009 not Endevo so I cannot help you on that front. And I don't actually pass around the ObjectManager. I actually have several ObjectManagers and have ManagerOfManagers so to speak to handle the sharing of the ObjectManagers. This in the end may have been overkill but the implementation was fun.

  13. This model isn't exactly what I'm doing in my real code, but it's closer. I have a reusable code package with two classes developers can use in their applications either directly or as parent classes for their own application-specific classes. In this example parent 1 is a simple counter with Increment Counter and Get Counter Value methods while parent 2 is a helper class that operates on parent 1 and makes a "Multiply by 2" method available. (They are shown with abstract methods but they could be implemented.)

    While writing an application a programmer realizes he needs a counter object that can also count down and handle negative numbers, but he can't change the reuse code package. He creates Child 1 to extend Parent 1 and adds the decrement method. Now his counter can count up and down. To correctly multiply negative numbers by 2 he creates Child 2 and overrides the Mult by 2 method. Inside that method he uses Parent1:GetCtr to check if the counter is positive or negative. If it is positive he uses Child1:IncCtr to provide the x2 functionality; if it is negative he uses Child1:DecCtr.

    Daklu, I was wondering if you tried to implement this using SciWare's approach of having the class's data members as a single DVR of a TypeDef and not creating a DVR of the object itself (see http://lavag.org/topic/10666-labview-oop-by-ref/). I played around with it a bit on your example and it does clean up the 'Application' part of the VI. All of the IPEs can be inside Get/Set methods. Makes the application programmer's job a bit easier in my opinion.

    There was an ensuing debate on whether this approach (DVR of data member cluster) was both 'in the spirit' of NI's implementation and safe from a race or deadlock conditions. SciWare any further thoughts on the latter issue? I do not see much risk beyond what is 'expected' when you share references to the same memory across threads.

    The project I am working on has a fairly deep class hierarchy. One branch of the hierarchy represents hardware components - motors, actuators, sensors, analog outputs. Another branch represents assemblies of these components (or other assemblies) - arms, grippers, thermal baths. My original thought was to have the assemblies hold a DVR to the hardware components. But without the ability of Dynamic Dispatch on a DVR the IPEs were simply too cumbersome. So, in comes SciWare's idea and the IPEs are now buried in the classes Get/Set (sorry NI, Read/Write) methods.

    Yes, I am worried about deadlock conditions. And a bit worried about performance, but since I am controlling slow mechanical devices (e.g. benchtop robots), speed is not really a concern.

    I am hoping that others out there are also trying this. I too will give some feedback as my design get implemented a bit further.

×
×
  • Create New...

Important Information

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