Jump to content

K-node

Members
  • Posts

    90
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by K-node

  1. The "Parent Class" property requires that you open a reference to your library (refnum, not object), which you can't do at runtime, so RT is excluded too.

    The Get LV Class from Path primitive works on RT, but the hierarchy can only be found, as stated by AQ in another thread Mike mentioned, through hacking the XML. But this solution has not been posted yet, to my knowledge anyway.

    Maybe I misunderstood the OP. I thought he wanted the name of the class and the names of its ancestor classes not the complete hierarchy of a class, that is, not including its children (descendants).

    He mentioned using a dynamic dispatch method, so this up the chain hierarchy would be determined at run time.

    Did I miss the objective here?

    Kurt

  2. NOOOO!!!!! :frusty:

    LabVIEW Class:Open MethodShort Name: LVClass.Open

    Available in Real-Time Operating System: No

    Why me?!!!

    Does someone know of a solution that works on a Real-Time system?

    Br, Mike

    I am not familiar with RT, but can't you use the Get LV Class Path vi and parse the name from that? Call your parent node vi and have it do the same thing? Each parent could append an array or append a string until you have a complete list?

    I can make an example if you need.

    Kurt

  3. I would like to know, if it is possible to read all attributes of a Labview class by getting an Array of Variants? I would like to have such a Read Method because I will use all attributes of my class as the description of a TDMS-File. The attributes Type Descriptor Name will be the Property Name in my TDMS and the Value will be the TDMS Property Value.

    Interesting challenge. I do not have a solution.

    From a different perspective, can you even do what you want with a arbitrary cluster? That is, go from a cluster directly to an array of variants.

    For a lame solution, the Read_All method has access to all of the class's private data. So you could just use the Unbundle method on the class's data, wire each element to the 'To Variant' method and build the array. Tedious, but perhaps better that calling all of the Read functions.

    Kurt

  4. Already have that, but I still have to match the "Run.vi" in the memory with the appropriate object. This is the problem I'm trying to solve.

    Br, Mike

    Do your 'Run.vi's have a control on the front panel that *is* the parent object - like SciWare's Process.vi has an the object control in his ActiveObject framework?

    If so, can't you go get the value of that control and cast it to your desired object. This should be the instance of the object that launched the Run.vi, or am I missing something here.

    Alternately, each of your ActiveObject could keep a list of the Run.vi's it launched and then you could exhaustively search for the reference that matches in all of the ActiveObjects your app created. But I like my other idea better.

    Hope this helps.

  5. I am so ecstatic that others are trying to push the process of using dynamic user events w/ objects in with LV and bundling/collecting references, as I've been attempting to do the same for a long time and felt pretty alone

    It is how I feel here at work. They have not appreciated the concept of OOP.

    But the basic premise of this change, is that you use a register event node to properly name everything, and then when it comes time to actually wire in the references, that portion of the code is a bit cleaner.

    Very nice suggestion. I added this approach to the project, the new vi is called: Main_ViaMultiUserEventRegEvents.vi.

    EventInClass_v2.zip

  6. OK, to polish my original post off and to help those that might be following along, I attached a project that shows

    1) the problem (see Main.vi) where all the events have the same name and the event structure is tought to figure out what is what.

    2) a solution as identified by mje (see Main_ViaTypeCast.vi) where we Type Cast the Object's event to an identical Event Refnum, but named differently.

    3) a solution as identified by Jarrod S (see Main_ViaRefnumBundle.vi) where we bundle each of the Object's events into a previously created cluster with uniquely named events.

    4) a solution also identified by Jarrod S (see Main_ViaRegistrationBundle.vi) where we bundle the Reg Events of each of the Object's events into a previously created cluster with uniquely named Reg Events.

    I hope that they are clear enough. Post here or PM me if you want.

    Anyway, I am liking #3 because I do not have to unbundle before I UnregisterForEvents. #2 has a similar feature, but as mje says, it is ugly.

    Also for you self proclaimed novices, explain to yourself why the EventCode value increments by 2 (as opposed to 1) for each button push. It is pretty obvious when you think about it, but, embarrassingly, it took me by surprise. It was a 'Well Duh' moment - I seem to have those way too often.

    Have a great weekend!

    -kugr

    EventInClass.zip

  7. Looks like it might be a bug with the second RegEvents prim not registering the second event. In your vi Hover Over 2 wasn't firing a Mouse Leave event. When I placed Mouse Leave before Mouse Enter in the RegEvents prim the Mouse Leave event was firing but the Mouse Enter event was not. Breaking those two events out into two separate RegEvents prims made everything work right. (LV2009)

    post-7603-127436964752_thumb.png

    I think this is what bean was referring to in http://lavag.org/top...n-event-refnum/. See post of May 13th where bean says:

    "Just make sure you only do one event per Event Registration Refnum when bundling the Event Registration Refnums into a cluster. I originally tried to group "sets" of events this way and revealed a bug. But, the way Ton has displayed will work since he just has 1 event (in this case, user event) per Event Registration Refnum."

    However this does not seem to be the bug of CAR 148149 (http://zone.ni.com/devzone/cda/tut/p/id/9996#148149_by_Date). Which deals with mapping event to case problems.

    I could not find anything in my quick scan of the 2009 SP1 known issues.

    -kugr

  8. Can you elaborate on this? Is it the coding that gets mixed up or does the event structure itself dispatch the event to the wrong frame?

    In my case it is that the event structure that seems to get messed up. The frames have the right code. The event condition that they were originally associated with got switched or removed and replaced by an existing one. I am not sure what caused my remap. I originally thought it was because of the similar names. It may be related to this:

    http://lavag.org/top...dynamic-events/

    At the moment, in my large app, I do have an Event Structure where an event is listed in multiple cases and I know I did not do that. I have not fixed it yet as the project is idle at the moment.

    As for distinguishing the events, can you rename the wire via a cast? It's ugly, but might solve the problem of having similarly named frames I'd expect?

    I am OK with ugly if it is the prettiest work around. Thanks!

    -kugr

  9. This question was moved from the Application Design & Architecture forum ( ) as it extended the OT a bit much.

    So, I have created a Class (call it MyObj) that has refnum to an event held in its private data, the refnum is called MyEvent. The creation of the event uses a strict type def control (call it EventMessage). Each instance of MyObj will have its own event refnum, MyEvent.

    Here's the rub. Since the events are all created the same way, they have the same name (MyEvent). When I wire the event refnum into the Reg Events vi, I get a collection of the same named entries. Then when I try to handle these events in a Event Structure I get identically named cases (<MyEvent> : User Event), the only way I have been able tell them apart is to add them as cases in the order they were added to the Reg Events. On more than one occasion, the mapping (event instance to case) has gotten mixed up. There are some threads discussing this as well as a NI bug report.

    Is there a better way to do this?

    TIA

    -kugr

    post-16231-127428249601_thumb.png

  10. Ah, so that is how my remapping may have happened. I have a little different scenario.

    In my case, I have a Class (MyObject) that has a UserEvent refnum as a member of its private data. For each instance of MyObject, a UserEvent is created with a Strict Type Def Control named MyEvent. When I register events from multiple unique instances of these objects, the event names are all the same ("MyEvent"). I have been using the order that they were listed in the RegEvents method as I add them to Event Structure. I have had cases where it seemed they got messed up - and even if they didn't I get confused as to which event is from which object.

    Is there a better way to do this?

    Thanks

    kugr

    I am going to move this question to the Object Oriented Programming forum.

    -kugr

    (edit: added link to topic)

  11. I have seen remapping to other events, if you edit clusters.

    Are you referring to what Jim has posted here?

    Ah, so that is how my remapping may have happened. I have a little different scenario.

    In my case, I have a Class (MyObject) that has a UserEvent refnum as a member of its private data. For each instance of MyObject, a UserEvent is created with a Strict Type Def Control named MyEvent. When I register events from multiple unique instances of these objects, the event names are all the same ("MyEvent"). I have been using the order that they were listed in the RegEvents method as I add them to Event Structure. I have had cases where it seemed they got messed up - and even if they didn't I get confused as to which event is from which object.

    Is there a better way to do this?

    Thanks

    kugr

    post-16231-127420610938_thumb.png

  12. OK, Daklu, count me in. I wish these mid-level components were around months ago. I expect that I can give 4+ hours a week, perhaps more depending on how I can integrate the effort with my current projects. I have OO experience, so I can do some development, examples and documentation. Architecting is a possibility, but I am not good at UML type presentations.

    Is anyone going to NI Week? Perhaps it would be beneficial to meet. I have not made any arrangements - including begging for money from my management - but I might consider this. I would also have to see if I can grab some other resources (conference call, webex, etc.) if this is of interest - though that does not always work well with international schedules.

    -kugr

  13. Geez Kugr, this was six months ago... you expect me to remember? wacko.giflaugh.gif

    LOL. I had some time (procrastinating on the documentation), so I was reviewing old posts.

    I'll review my code when I get some time and let you know what I find.

    That's OK. It is not important. I'd rather press ahead on new problems.

    kugr

  14. I've been thinking about starting an Object Oriented Design Challenge as a way to foster discussion about different ways to tackle problems in OOP applications. Lack of time has prevented me from contriving a simple problem to kick off the series, so I'll start with a fairly complex problem I'm facing.

    post-7603-125874455457_thumb.png

    Background:

    We have an (incomplete) test sequencer that by fortunate coincidence mostly works. Our application is set up with an abstract Test Case parent with the execution details encapsulated in child classes. We have an internal class library for our devices. The specific device to be tested (Dev1a, Dev2b, etc) is selected by the operator when setting up the test sequence. The device object is passed into each test case before executing it.

    The station has been designed now needs to test devices in any one of four test positions. We have internally built switch boxes to control the communication path and signal path to each of the test positions. I wrote drivers (CommMux and SigMux) to control the switch boxes.

    The problems:

    1. When starting a test case, the initial switch box settings depend on the test case, the device being tested, and the test position. If any one of those changes it requires a different settings for the switch boxes. Switch box settings may also be changed as part of the test case. (There is more to them than just a mux.) New test cases and new devices will be added in the future. No new test positions will be added to the station. (So they say...)
    2. It turns out that we also have to communicate with the devices before any test cases are started, or have even been selected. This communication path can be determined based on the device and test position--it doesn't depend on the specific test case.

    The questions:

    With 37 test cases, 12 devices, and 4 test positions, how would you add this functionality into the application in a way that promotes the expected extendability, without creating a separate case for each combination? How do you structure this in a way that the functionality is available to solve problem 1 and problem 2?

    I have some thoughts on ways to go about this, but I'll withhold them for now so I don't pollute the idea space. smile.gif

    OK, Daklu, time for some fun. How is your solution to this going?

    If I understand this correctly...

    SwitchBoxSettings_Initial = f(TestCase, TestDevice, TestPosition)

    SwitchBoxSettings_Changed = f(TestCase)

    and

    CommunicationPath = f(TestDevice, TestPosition)

    Is the SwitchBoxSettings_Changed also a function of SwitchBoxSettings_Initial and does it change over the duration of the TestCase? Would it need to notify a client that it is time for a change?

    I am leaning toward a SwitchBoxSetting class and probably a SwitchBoxSettingManager. Each SwitchBoxSetting instance would retain the trio that defines it along with all of the settings native to the SwitchBox. The SwitchBoxManager could return a SwitchBoxSetting for the trio of TestCase, TestDevice and TestPosition. It would run through it's internal collection of SwitchBoxSettings and return the one (or perhaps set) that qualifies.

    I have created my own ISerializable interface and SerializationInfo class that allows me to write the structure of a class to an XML file and later read it in. It would be possible to add new SwitchBoxSetting instances by editing the XML. You just have to know what the fields mean and the valid values. In my implementation, reconsituting the XML into LabView requires a 'factory' that can map class name to class instance. This eliminates the need to change any LV code if a new SBS is required or an existing one needs to be altered.

    Right now I am avoiding the issue of SBS_Changed. It can be implemented via a Manager approach, but I am not completely sure how it works.

  15. Kugr! Welcome back! I haven't seen you since last fall... thought maybe you and SciWare fell of the edge of the world. laugh.gif

    Thanks, Daklu. I have been lurking about, but have not posted. I have been immersed in my project which is heavily 'class data in a DVR' based. And I use interfaces, lots of interfaces, perhaps too many. It is very similar implementation to what you proposed some time back. I have not seen Jim Kring post is a bit either. He was a pretty early adopter of LVOOP.

    The project is essentially over - a prototype of sorts showing that we can do it if we need to. So it goes on the shelf for a bit while I write up an internal report on the implementation. There is very little knowledge on OOP for automation so part of the report is some fundamentals.

    (And, seeing as how I freely critique others' code, I expect no less in return. Let me have it! smile.gif )

    I always liked your programming style and your justifications for your approach - I still do. I was disappointed that the additional ornaments on the VI icons were missing (remembering the cell phone and baby example).

    Because I am so focused on 'DVR the data', I would have DVR'd the data somewhere. My first thought was to do this in the Bag class. Then I thought again and I think I would have the DVR in the BagImplementation class. This would hide the Create and Destroy methods (needed to allocate the DVR and release it) from the user of Bag. This also means that BagImplementation needs Dynamic Dispatch methods of Create and Destroy. They would be no-ops in general. In my project, I started on an idea of IMemberVarsDVR interface and that a factory that created a new instance of any class would attempt to cast the object to this interface and if successful would call the Create method. This was late in the project and was not worth the change. Anyway, I could see something similar working here. Not sure that is the right approach though.

    If anyone wants to collaborate on reusable collection modules let me know.

    It would be very cool to also make this part of a large® framework. I am trying to take my group into the OOP realm and need to make things as easy as possible. I'd be willing to help out on this. We should probably start a separate thread. If others join in, that would be great.

    Kurt

  16. The main reason why I place the entire object into the DVR instead of just the object properties is because I am working on recursive functions. In particular I call method X on object A. Object A has a ref to the next Object B, so then method X recurses on object B, and so on and so on. If the DVR only encapsulates the data and not the entire object, I don't think you can do that.

    I am not sure that limitation exists, at least in how I implemented this concept.

    Yes, the DVR only 'encapsulates' the data, but one of the pieces of data is the sibling object. So inside Object A's method X, we dereference Object A's data getting its sibling object (Object B) and call its method X.

    As Felix encountered, LV will not allow me to actually put an object of its own type in its private data cluster (that would exist in your approach too *see edit). So, you need to have a parent object. It could be the LV Object, but then I would have to send it through the 'to more specific class' function. In my recursion, I created a parent object with method X supporting dynamic dispatch (and reentrant execution).

    Personally, I prefer the 'DVR the object' approach. The constant need to dereference made it to cumbersome. The only way to encapsulate was to add a wrapper layer and that was a non-starter.

    -Kurt

    edit: I think I am wrong about the need in your approach. The refnum is probably hiding the fact that the object is the same type.

    edit2: I thought again. You still need some parent object.

  17. You are really getting into this OO stuff. Very nice!

    a) rewrite the array as an list object (gives a bad performance).

    I have implemented this approach and I will admit that performance was not a design constraint. However, I would think that the performance impact can be minimized based on the implementation. First, if you implement a <List> class where it itself has a DVR with the data, then the 'owning' class does not have to have the <List> object in its DVR. This eliminates one de-reference IPE. This assumes that you don't mind having a mix of DVR and non-DVR data in an object's private data cluster. For my basic <List> class is is basically a wrapper around LV's own Array. I have added the method call overhead for Add, Remove, etc. so there is that hit on performance. But if the <List> is really a collection of objects, then I can pass a 'target object' into the wrapper representing "Index Array" to perform the "Preserve Runtime Class" method and have the method return the entity in the list correctly cast.

    b) provide a class locking (semaphores) so I can code lock, checkout, modify, checkin, unlock

    I can see a use for this even if "a)" was implemented. Locking access to the list would suspend other threads from either modifying or obtaining stale data. I am assuming that the checkout method would return the 'Array' and the checkin would accept it.

    c) write the add, clear ... methods for each 'list'

    I do not like this approach from the replication of code. And are you just wrapping the 'Array' methods? This does not seem to eliminate the performance lost there.

    Any better approaches.

    I've got nothing.

    Keep up the questions and share your experiences. My implementations have worked for me, but I am currently a sole developer at least in LVOOP here. My background is in text based languages C/C++/C# and only re-started programming in LV last June (after a 20 year hiatus).

    -Kurt

  18. My first approach (and I see the same in the Tree code from GoGators) was to put the object into the DVR. This seems to be a direct translation from other OOP languages with their pointer based by-ref concept.

    So today I realized that I also can place the data inside a DVR, make the object private data only the DVR and have the referencing/dereferencing inside the accessor methods of that object. This looks much better, as I 'hide' the by-ref implementation from the user (means they need to know nothing about DVR and IPE and less effort to code because they need to be coded only once).

    I prefer the data inside a DVR. As you noted, this does make for a very clean interface. I generally define a single strict type data as a "Strict Type Def." control. This thread, if you have not reviewed it yet, has some good information:

    http://lavag.org/top...iew-oop-by-ref/

    The self-referencing seems to work the same way via a parent class (placed inside the data TD inside the DVR inside the private data).

    LabVIEW is clever that way. I find it a pain to deal with the casting ("To More Specific Class"), but all of this can happen in a "Get Sibling" method or some such thing.

    Do these two approches to by-ref differ considerably? ...a general judgement approach A or B is more robust.

    Nuances of race conditions, etc. aside, I am not sure if one is more robust than the other. In my project, I used the inner DVR approach. Though this requires a 'Create' and 'Destroy' method which are just begging for some sort of automation via scripting, I still find the approach very clear especially when I actually get to use the class.

    -Kurt

  19. I recently tried to use DVR's with LVOOP, but I evidently use it the wrong way, since it doesn't work as I want.

    But the question is: Why can't I use DVR's this way?

    (see this simple project: ClassTest.zip)

    Lief,

    My quick take...

    In the getClass2Reference.vi method, you are returning a reference to a copy of the Class2 instance that Class1 maintains. For simplicity, I always assume that when a wire is branched, the data is copied. So in this case the copy does not share the same memory for Class2's member variables (aka private data), String1 and String2.

    If you had a setClass2Reference.vi method which accepted a reference and used the dereference value to set Class1's member variable it would work. That would be kind of a silly solution - not sure what value the DVR brought you.

    Some of us have made the member variables of a class a DVR. So, any copies from a branched wire will still point to the same data. Care should be taken with this approach and you will find lots of discussion on this topic in this forum.

    Others make the class itself a DVR. Again, branches would have identical DVRs so any dereference would get you to the same data.

    Hope this helps.

    -kg

  20. -string GUID // all objects must have a guid

    The idea is that when an object is created at run time it generates a GUID

    This is slightly off topic: This VI which came in my installation of LV2009 provides a solution to creating a GUID...

    C:\Program Files\National Instruments\LabVIEW 2009\resource\Framework\Providers\API\mxLvGenerateGuid.vi

    After writing my own quasi-unique method, I found this little gem (grrrr-r-r-r-r). It may also be in earlier versions of LV.

    Is there another VI already native to the LV Functions palette for creating a GUID? I looked at a few hits from searching the LAVA forums but did not see any reference.

    -kg

  21. Miha,

    Ah, I see what you are trying to do. I have never used this approach yet. To get close to what is there...

    I added the Open VI Reference function to my block diagram

    I right clicked on the type specifier node and selected Create Constant.

    I then right clicked on the newly created constant and selected Select VI Server Class. From that submenu selected Strictly Typed VIs.

    Listed in that was Generic Plugin.lvclass, this was not in my project, but I added one later and the constant turned red.

    Sorry, this sounds very non-technical, but perhaps it will get you farther.

    Kurt

  22. Mike5,

    This link will describe many of the design patterns...

    http://decibel.ni.co...t/docs/DOC-2875

    In particular it has a zip file with an implementation of the factory method. While it does not create a static VI reference since a class is really not a VI, it uses the path of the class and converts it using the Get LV Class Default Value VI. This implementation is interesting because it does not load the desired class into memory until the Load By Enum VI is called (this VI is part of the project).

    There are alternate ways to get the Factory to understand what classes it can create rather than an enumeration. Perhaps it could have a registration method where some other VI tells it to add a class path to its list - creating something like a name-value pair (probably implmented as two arrays - one with name, the other with path). The name would be something your application would use to tell the Factory to create. The value would be the path to the class. Alternately, if memory does not concern you, you can give the Factory an instance (rather than a path) of the classes it creates. The Factory would simply return the entry in its list based on the name it used to look up. Remember that as a data flow language, the class the factory got out of its list is an independent copy (unless you start using data value references in the class's private data). More on the DVR when you get to that point - there was an earlier thread on that subject.

    I hope this helps.

    Kurt

  23. The PreserveRuntimeClass prim would be inside Interfaceable:GetInterfaces, meaning the Interface is returned to the class user correctly typed and the user doesn't have to use either prim to downcast to a specific Interface.

    Ah, thanks. Now I see how it works. It seems I have some retrofitting to do in my project.

    I have some questions regarding using interfaces that anyone is free to respond to:

    1. Assuming GetInterface takes an Interface object as an input instead of the Interface's name as an input, is it useful to have a GetNames method that returns a string array of Interface names that an object supports? The more I think about it the more I have a hard time coming up with a valid run time use case for it.
    2. Is a GetInterfaces method that returns an array of supported concrete interfaces useful at runtime? The only use case I can think of for this is to check an interfaceable object to see if it supports a given Interface, and I think a better implementation is to simply raise an error in GetInterface if the class does not support that Interface.

    For #1, I have implemented this approach and GetNames is no longer used. I removed the InterfaceBag class too actually. In the GetInterface method, since you are asking for an interface (ISleepable) and not the implementation (ISleepableBaby) you cannot do a direct comparison, I had to use a PRT. If successful, then the implementation (ISleepableBaby wired from PRT's object out value) is returned.

    For #2, I do not see how I would get the implementation given the interface without obtaining a list of concrete implementations to compare against (or an equivalent call to the Interfaceable object). The only entity that knows what it implements is the particular Interfaceable object. Maybe I missed something.

  24. Minor update: v0.9.1

    I did not see the attachment, but the changes were straight forward to implement.

    Ultimately there are lots of ways _GetInterfaceBag.vi can be implemented. The only thing that matters to the framework is that it returns an InterfaceBag object that contains all the concrete interfaces the class exposes.

    I actualy removed creating the interface bag at the _GetInterfaces method returning just the list. It is up to Interfaceable.GetInterface to populate the bag or even just work off the obtained list since the _GetName can be called for each Interface.

    Summarizing your suggestions from your "sibling search" post ( http://lavag.org/topic/11186-ideas-for-an-issibling-algorithm/), I think you were suggesting that the GetInterface method accept an object derived from IUnknown instead of using the name since all IUnknown derived objects must implement the _GetName method. Is that what you suggested? I like it - saves typing (and typos)!

    And also you were saying to use the PreserveRuntimeClass function as opposed to the ToMoreSpecific class after obtaining an interface from GetInterface. Am I correct? I have to reread what AQ said about those two functions.

    So, now for the question...

    Let's say you have a SmartCellPhone class that derives off of CellPhone. Would you expect it to implement the ISleepable interface, or utilize the CellPhone class capability? This may be a more fundamental question on interfaces. I have implemented interfaces, but I have never derived a class that had an interface (or at least did anything about it if it had one).

    Thanks for sharing this framework.

  25. 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

×
×
  • Create New...

Important Information

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