lvb Posted October 29, 2010 Report Share Posted October 29, 2010 I am running into a roadblock with implementing a design within LVOOP. I have a base class from which I would like to create multiple child classes. Each of these children should be singleton objects and I would like to override and implement one public function Command and Response "wireless" aka a LV2 style global. Basically, I am looking to re-use all of the functionality of the base class, but just have a wireless implementation for each "module" of the system. The structure of the base class is shown below: Remote Interface.lvclass Private Methods Create Destroy Interface VIG Public Methods Command and Response The Create method stores the class object in a VIG (LV2 style global). The Command and Response method calls the Interface VIG to get the current object. My first attempt was to simply create an override for the Interface VIG, but LabVIEW will not allow this with the following error: This VI attempts to override a static VI in an ancestor class. An ancestor class has a VI by the same name that does not have a dynamic dispatch input terminal. Only dynamic member VIs can be overridden in child classes. To correct this, change the name of this VI so that it does not match any ancestor VI names or edit the ancestor to include a dynamic dispatch input terminal. However, creating a dynamic dispatch input terminal would not allow for the Command and Response VI to call the Interface of each child. What is the proper architecture for this implementation? I have attached a sample project in LabVIEW 2009. Any help would be appreciated! Thanks Interface.zip Quote Link to comment
Jon Kokott Posted October 29, 2010 Report Share Posted October 29, 2010 I am running into a roadblock with implementing a design within LVOOP. I have a base class from which I would like to create multiple child classes. Each of these children should be singleton objects and I would like to override and implement one public function Command and Response "wireless" aka a LV2 style global. Basically, I am looking to re-use all of the functionality of the base class, but just have a wireless implementation for each "module" of the system. The structure of the base class is shown below: Remote Interface.lvclass Private Methods Create Destroy Interface VIG Public Methods Command and Response The Create method stores the class object in a VIG (LV2 style global). The Command and Response method calls the Interface VIG to get the current object. My first attempt was to simply create an override for the Interface VIG, but LabVIEW will not allow this with the following error: However, creating a dynamic dispatch input terminal would not allow for the Command and Response VI to call the Interface of each child. What is the proper architecture for this implementation? I have attached a sample project in LabVIEW 2009. Any help would be appreciated! Thanks I'm not sure what all the implications of this design pattern are, but it looks like it should work. You will definitely be duplicating data on every child class (the deeper the structure, the more data you will duplicate.) there are probably better design patterns for your implementation anyway. I I can't upload a snippet right now, but I'm thinking you can't do what you are trying to do in 2009. 2010 added the preserve runtime class which will allow you to override the functional global VI. Honestly I would go with an SEQ instead of a functional global. It would make understanding which object is being operated on much easier. ~Jon Quote Link to comment
lvb Posted October 29, 2010 Author Report Share Posted October 29, 2010 There are probably better design patterns for your implementation anyway Please elaborate! Quote Link to comment
Jon Kokott Posted October 29, 2010 Report Share Posted October 29, 2010 I'm not sure what all the implications of this design pattern are, but it looks like it should work. You will definitely be duplicating data on every child class (the deeper the structure, the more data you will duplicate.) there are probably better design patterns for your implementation anyway. I I can't upload a snippet right now, but I'm thinking you can't do what you are trying to do in 2009. 2010 added the preserve runtime class which will allow you to override the functional global VI. Honestly I would go with an SEQ instead of a functional global. It would make understanding which object is being operated on much easier. ~Jon you can do it in 2009. Pull the input input outside of the case structure. (no dynamic dispatches allowed inside a structure.) The input needs to be "Dynamic Dispatch" the output terminal needs to be "Static Dispatch" and the parent class type, you should see a coersion dot on any child overrides. you'll have to put a "To more specific Class" vi on the outside of the subvi call of wherever you actually wanted that dynamic dispatch output behavior, because without the preserve runtime class you can't do this. ~Jon I'll take back the data duplication comment, so long as you don't use a call parent method on any of your LV2 globals. Quote Link to comment
Jon Kokott Posted October 29, 2010 Report Share Posted October 29, 2010 Please elaborate! OK, so what you are doing is creating a single object manually by defining a new class for each object. This is not very extensible. lets say you write a sweet group of VIs, but now you need to have multiple instances of a particular child class. You can't add multiple objects by making the LV2 global reentrant and calling it by reference like a standard LV2. Dynamic dispatch VIs cannot be called by reference (you can't preallocate clones so you wouldn't know what instance you were operating on anyway.) Additionally this pattern means that you will be constantly instantiating the default data type of your child class in order to read its actual data. If your default data type has some huge memory profile, you'll have to load that without gaining any functionality (big memory profile, slow performance, effectively nullifying the biggest advantage for a LV2) If you want to do by reference with LV2 and LVOOP, don't make the container (your Functional Global/LV2) itself dynamic dispatch. Use the normal by reference LV2 (open VI reference, make sure it is reentrant, preallocate clones.) You can still chuck whatever child data type you want in there, but your output will always be casted to the parent type. you'll be using the to more specific class constantly, and keeping track of who is who might be too big of a pain to make it worth it. If you want the correct data type to come out, you'll have to make a new LV2 for every data type you want to support (you were planning on doing this anyway i suppose.) Otherwise, as I said before, I'd recommend using an SEQ (Single element Queue.) There is lots of support out there for this design pattern. Its easy to understand what object you are operating on because you are required to wire the object reference (queue reference.) I'll upload some pictures when I get off work. ~Jon Quote Link to comment
Aristos Queue Posted October 30, 2010 Report Share Posted October 30, 2010 Nevermind. Quote Link to comment
Francois Normandin Posted October 30, 2010 Report Share Posted October 30, 2010 I can't upload a snippet right now, but I'm thinking you can't do what you are trying to do in 2009. 2010 added the preserve runtime class which will allow you to override the functional global VI. Just a quick note to say that the Preserve Runtime Class primitive was added in 2009. Quote Link to comment
Jon Kokott Posted October 30, 2010 Report Share Posted October 30, 2010 Just a quick note to say that the Preserve Runtime Class primitive was added in 2009. Ok so here is how you make your dynamic dispatch FG. All childs that override this shall follow this pattern. both the input and output are dynamic dispatch. here are the problems with this type of architecture: 1. In order to access your data store, you must have a copy of the class you are trying to access. In a normal LV2 this is not the case because you do not need to wire the input of your VI. When you do dynamic dispatch, you must wire the connector pane or it will not know what vi in the inheritance tree to load. 2. You cannot extent this pattern beyond one instance per named VI. Creating a bunch of different VI's for data stores is time consuming and you'll never be able to create enough for some applications. Here is what an SEQ would look like: and here is your by ref LV2: Or DVR: the wire wont be broken if you are creating it inside a class member VI. these are the main ways to do an object by reference. I prefer SEQs over every other data store. You can get some extra capability out of them if you are interested in learning how. ~Jon Quote Link to comment
lvb Posted November 4, 2010 Author Report Share Posted November 4, 2010 Jon, Thanks for your prompt response. Unfortunately, I have been tied up and not able to review the post until now. I am not clear on your previous response. Could you attach the modified project shown in your response? Also, I would be interested to hear the advantages of a SEQ. Thanks for sharing your knowledge! Quote Link to comment
Jon Kokott Posted November 9, 2010 Report Share Posted November 9, 2010 Jon, Thanks for your prompt response. Unfortunately, I have been tied up and not able to review the post until now. I am not clear on your previous response. Could you attach the modified project shown in your response? Also, I would be interested to hear the advantages of a SEQ. Thanks for sharing your knowledge! I'll attach the modified project when I get off work. Here are the reasons I like the SEQ as a data store Vrs by Ref LV2 1. I find it annoying to access methods by locating the editable VI in the project (or static VI reference at initialization) then shopping through a deep case structure (it is not uncommon to have an enum with like 40 cases in it) 2. If you create a lock condition, their is no way to time yourself out and reattempt (this is a bad thing to be doing but if you need a quick fix atleast you can do it with an SEQ) Best thing about LV2. Fastest code in the bunch. Tried and tested since before I ever started using labview. Reasons why I don't like DVRs 1. It is SUPER annoying and code intensive to make methods. Simple method access is 10+ mouse clicks after dropping the VI you want to run. It ends up looking ugly as hell and you have to make a wrapper to clean up the mess. (manual procedure looks like drop inplace, add dvr in/out, drop method inside, drop preserve run time class at end, wire in/out terms, drop merge errors, merge errors in a specific order edit->create subVI save new subVI.) <- I probably won't ever use DVRs until they integrate Invoke nodes to do all this stuff for you (LV2012 probably) 2. you can't swap the data type in the store. (Also not a great idea unless you know what you are doing) 3. Same lock condition as point 2 above 4. The property node feature (2010) doesn't work (for me, some people don't seem to experience the problems i do.) Best thing about DVRs: I really don't like these right now. Its too much coding for next to no benifit. (these are marginally faster than an SEQ. If I need that extra speed, I'll pick the LV2 and more than likely optimize the portion that needs to be fast. this is usually a pointer to a pointer (ie reference to a reference for labview) situation where so that I can chop down the bottleneck part of the code to primitives only with no class functionality anyway.) Nice to things from SEQ Preview Queue/lossy enqueue primitive (you can implement this with the other 2.) Timeouts on data store access (good for when you don't have time to find the place where you screwed up and didn't follow a data access rule.) Really well developed and understood design pattern. But don't take my word for it. Their is a ton of material on all these online. here are your kewords: Singelton Design Pattern (these are all singletons) SEQ (single element Queue) DVR (Data Value Reference) LV2 (Functional Global, Action Engine, and LCOD (I forget what the acronym is for but i'm sure google can figure it out)) On a side note. if you look at the Config File VIs from 8.6 or prior they used a pointer array stored in a LV2 (really a terrible bottleneck for larger applications so I didn't bother to discuss it) In 2009 they updated this architecture to SEQ. You should have access to both in your VI lib. Take a quick peek at them to see some code that thousands of people have used successfully. I hope this helps. ~Jon Quote Link to comment
Jon Kokott Posted November 9, 2010 Report Share Posted November 9, 2010 I forgot one other really nice thing about by ref LV2: you can insert the front panel into a subpanel while you are running to create an easy spy for what the state of the data is. This can be very helpful for debugging. ~Jon Quote Link to comment
Aristos Queue Posted November 11, 2010 Report Share Posted November 11, 2010 2. You cannot extent this pattern beyond one instance per named VI. Creating a bunch of different VI's for data stores is time consuming and you'll never be able to create enough for some applications. Doesn't have to be... make the VI reentrant and use Open VI Reference to give you a new reentrant clone each time you want a new LV2-style global instantiated. Quote Link to comment
Jon Kokott Posted November 11, 2010 Report Share Posted November 11, 2010 Ok so here is how you make your dynamic dispatch FG. All childs that override this shall follow this pattern. both the input and output are dynamic dispatch. here are the problems with this type of architecture: 1. In order to access your data store, you must have a copy of the class you are trying to access. In a normal LV2 this is not the case because you do not need to wire the input of your VI. When you do dynamic dispatch, you must wire the connector pane or it will not know what vi in the inheritance tree to load. 2. You cannot extent this pattern beyond one instance per named VI. Creating a bunch of different VI's for data stores is time consuming and you'll never be able to create enough for some applications. Doesn't have to be... make the VI reentrant and use Open VI Reference to give you a new reentrant clone each time you want a new LV2-style global instantiated. Reentrant dynamic dispatch VI called by reference? I do not think that will work. I believe you are refering to this pattern: and here is your by ref LV2: ~Jon Quote Link to comment
Aristos Queue Posted November 13, 2010 Report Share Posted November 13, 2010 Reentrant dynamic dispatch VI called by reference? I do not think that will work. Not directly... but you make a static dispatch full reentrant VI in your ancestor class that wraps around the dynamic dispatch VI shared reentrant core VI. Instantiate the static dispatch VI whenever you need another LV2 style global. For bonus points, check out the LV2OO style global. 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.