Popular Post hooovahh Posted July 20, 2015 Popular Post Report Share Posted July 20, 2015 So here is a fun little nugget I worked on over the weekend. At our local user group there was discussions about action engines, and functional global variables. People talked about how a Action Engine, that has several cases like, Init, Read, Write, Close, will have inputs and outputs that just aren't relevant to every method of that VI. So people said how they some times write wrappers to their FGV where each VI is a unique value for their enum. This allows them to delete the unneeded controls and indicators, making for an easier to understand API, where only the important inputs for that method are exposed. So I wrote some code to demonstrate how to accomplish this with scripting. I figured this function might be useful to others. Included in the zip is an example VIG that can be used to demonstrate how it works. FGV Wrapper Maker.zip 4 Quote Link to comment
Bobillier Posted July 20, 2015 Report Share Posted July 20, 2015 Thanks Hooovahh Is it possible to have it in LV2011 ? Eric Quote Link to comment
hooovahh Posted July 20, 2015 Author Report Share Posted July 20, 2015 Saved in 2011 FGV Wrapper Maker 2011.zip Quote Link to comment
pawhan11 Posted July 21, 2015 Report Share Posted July 21, 2015 (edited) Nice Idea, I always have the problem with connecting this enum and unbundling what needs to be used from cluster In one project I ended making polymorphic wrapper in similar way You did and then unbundling what is needed inside wrppers. It takes some time doing it one by one and they all look the same so it is bit confusing but if polymorphic vi can be scripted on top of that wrappers it will be nice Edit: added polymorphic vi generation after Edit2: if there could be easy way to do bundling/unbundling by scripting, not by hand it would be nice fgv to polly.zip Edited July 21, 2015 by pawhan11 1 Quote Link to comment
ShaunR Posted July 21, 2015 Report Share Posted July 21, 2015 Hmmmm. This got me thinking (always a problematic occurrence) If we combined your scripting stuff with the ideas of OMeta we could create a Requirements Spec Translator and convert specs directly to LabVIEW like they do in the CLA exams - make all the CLAs redundant Quote Link to comment
hooovahh Posted July 21, 2015 Author Report Share Posted July 21, 2015 Edit: added polymorphic vi generation after Edit2: if there could be easy way to do bundling/unbundling by scripting, not by hand it would be nice That is a fantastic addition. As you can see from the disabled code on the right I was trying to make a unique icon for each wrapper because I didn't like that every VI had the same icon. I didn't quite get it working so I gave up, but with a polymorphic VI you can see the VI Selector which tells you which instance it is using. As for the cluster idea, yeah each VI that is made can have the cluster elements it actually uses be exposed on the palette of that unique value of the method. So if you have a cluster with a path to load and a string to write, in your Init VI just have the path be on the front panel not the cluster, then in the VI bundle that into the cluster that goes into the FGV core VI. In this way the Init VI only has the things that are important to it on the connector pane, and it makes it easier to understand how the user is supposed to use the API, rather than throwing a bunch of controls that will be ignored on the FP. Using more scripting I think you could choose which data is important for each instance, or even detect it in some cases, but that would be a ton of work. I'd suggest just doing that manually. Quote Link to comment
crossrulz Posted July 21, 2015 Report Share Posted July 21, 2015 So here is a fun little nugget I worked on over the weekend. At our local user group there was discussions about action engines, and functional global variables. People talked about how a Action Engine, that has several cases like, Init, Read, Write, Close, will have inputs and outputs that just aren't relevant to every method of that VI. So people said how they some times write wrappers to their FGV where each VI is a unique value for their enum. This allows them to delete the unneeded controls and indicators, making for an easier to understand API, where only the important inputs for that method are exposed. I do this as well. But I take it one step further and have it all inside of a library. I then make the Action Engine and the enum controlling it private. This makes it so that the API is nothing but the wrapper VIs. It helps by keeping other people away from the AE and screwing something up. I can't wait to look at your code here. Sounds like something I could possibly use. 1 Quote Link to comment
hooovahh Posted July 21, 2015 Author Report Share Posted July 21, 2015 I then make the Action Engine and the enum controlling it private. This makes it so that the API is nothing but the wrapper VIs. Oh this is a good idea too. I added code to create a library and add all the members. This works just fine but I couldn't find a way to set the access scope through scripting. Is there a method for that? Quote Link to comment
pawhan11 Posted July 21, 2015 Report Share Posted July 21, 2015 Never scripted lib before but found this: Quote Link to comment
hooovahh Posted July 21, 2015 Author Report Share Posted July 21, 2015 Oh thank you, I was trying to perform the action on the Library item, not he library itself. Attached is an updated version which now makes a library, adds the core, the polymorphic VI, and the polymorphic instances, and sets the core to private. It should probably be put in a virtual folder for Public and Private, but I was just happy to get this working, feel free to improve on it. Main Generate VIG Wrappers With Library 2014.zip Quote Link to comment
bbean Posted July 21, 2015 Report Share Posted July 21, 2015 I added a delete feature to your latest version that will delete the controls for each case if they are not wired inside the case structure of the FGV. Its not perfect and I had to rename the initialization constant in the example FGV so it doesn't delete the input terminal (the constant had the same name). Anyway thought I'd throw it out there. Generate VIG Wrappers with Delete 2014.zip Quote Link to comment
hooovahh Posted July 21, 2015 Author Report Share Posted July 21, 2015 I added a delete feature to your latest version This is good, but I don't think it will work for everyone. I've seen some cases where there is only one input and it is a cluster, and then it will unbundle that and only use some elements of it in each case. I can't remember a time I've done that so your version is perfect for what I've done. We could try to get crazy and look into unbundleing and seeing what elements are used in each case too. Quote Link to comment
Yair Posted July 22, 2015 Report Share Posted July 22, 2015 I haven't looked at the code, but there are also other ways of doing this. If you think about an FGV, it's essentially just a way of performing different actions on the same piece of data. Your code creates a wrapper to turn the actions into VIs. If you're doing that, you can also just pull out the data and get rid of the internal FGV entirely. For example, the shared data could be a cluster (or an object) in a DVR. Each action simply takes the DVR and operates on the data, so the "increment num" action could look like this: It starts with a call to the GET DVR VI (inlined into the caller here for simplification) and then does the action. This allows you to get rid of the enum and the FGV VI itself and the need to match the API correctly. It might make debugging more difficult, because you no longer have a single VI you can go and probe to see what's happening. Quote Link to comment
ThomasGutzler Posted July 22, 2015 Report Share Posted July 22, 2015 (edited) I see a FGV as a singleton class, which is very similar to what Yair suggests and thanks to GDS we can create a Singleton class within 5 minutes File IO Action Engine_class.zip File IO Action Engine_class 2012.zip What I can't do in 5 minutes is fix the scripting up so it generates that for me but I imagine that it can't be too difficult from what hooovahh started off with Edited July 22, 2015 by ThomasGutzler 1 Quote Link to comment
hooovahh Posted July 22, 2015 Author Report Share Posted July 22, 2015 For example, the shared data could be a cluster (or an object) in a DVR. Each action simply takes the DVR and operates on the data, so the "increment num" action could look like this: Interesting, I never thought of doing it this way. Now there are a few draw backs, as you mentioned first you don't have just some central core VI that you could probe to see how everything is doing and the last states executed. There are also times when I have more than one shift register, so that would mean either more DVRs or more practically, a cluster of the things I want. Oh and you'll have an extra step you need to remember to close the DVR reference where a VIG is fine to just go idle. For me action engines are so damn convenient. I can make one is literally seconds, okay I have a template for a read/write VIG as a starting point so maybe that's cheating but still. Probing is simple, execution is simple, developers of all experience levels can understand it (as long as they understand the concept of a uninitialized shift register), and adding it to a library can have some level of access protection. I'm not saying classes aren't a more elegant solution for the same problem. Oh and I love scripting by the way. Yesterday I spent most of the my day writing scripting code, that auto generates accessing VIs, messaging VIs, and type defs for a Web Service someone wrote. It would have taken me probably all week to do it all by hand, and there would have been lots of errors. Now when new code is written I run my script again and all the new VIs and controls are generated. Quote Link to comment
ShaunR Posted July 22, 2015 Report Share Posted July 22, 2015 (edited) It's all great but there needs to be thought about the pros and cons of doing this with polymorphic VIs and classes.The fallout is, that if you take the supplied example, you go from a single VI of 30kB so several VIs totaling ~180kB with no change in functionality. That's nearly a 6x increase in code size with a 7 fold increase in the number of VIs That's why applications take 10 hrs to compile When I choose to use a polymorphic VI, I make that choice very carefully as a trade off between user friendliness (the menus, adapt to type and terminal reduction) and code complexity and size. As I've said before, classes and polymorphic VIs bloat code and cause replication. The worst use would be to effectively just move the enum list of an AE to a poly menu "because it looks better". The tradeoff is the increase of the number of VIs and code size in proportion to the number of items in the enum list with consequences to performance, maintenance, compile times and understanding complexity with no change in function. The gain is a subjective aesthetic for a developer, not even an end user.. The best use is hiding controls unused for an enum item and logical groupings of functions.That is not easy to achieve with automatic wizards as there is no context that can be gleaned from the VI itself. It is very easy to create huge quantities of code and complexity with wizards though. Why, for example does the "Return Settings" need file terminals? How could we tell the wizard to not wire and create those terminals for that enum? Edited July 22, 2015 by ShaunR Quote Link to comment
bbean Posted July 22, 2015 Report Share Posted July 22, 2015 Why, for example does the "Return Settings" need file terminals? How could we tell the wizard to not wire and create those terminals for that enum? "Return Settings" doesn't need file terminals. If you look at the code I added to delete terminals, I use a very rudimentary approach where I check to see if the case selector tunnels are wired to anything in the case structure and delete the controls with the same name as the tunnels that are unwired. Its crude and probably not very robust at this point. I agree with you concerns about code bloat which is why I dislike polymorphic VIs. Would there be a generic way to do this with an Xnode FGV wrapper that goes through similar operations as hoovahs script, but self creates its inputs and outputs based on the case (enum) you selected from the Xnodes menu item? Would it be worth it? Or do you just transfer the complexity to the scripting environment where the potential for mistakes (and code errors) is more likely and less transparent? Quote Link to comment
ShaunR Posted July 22, 2015 Report Share Posted July 22, 2015 (edited) "Return Settings" doesn't need file terminals. If you look at the code I added to delete terminals, I use a very rudimentary approach where I check to see if the case selector tunnels are wired to anything in the case structure and delete the controls with the same name as the tunnels that are unwired. Its crude and probably not very robust at this point. I agree with you concerns about code bloat which is why I dislike polymorphic VIs. Would there be a generic way to do this with an Xnode FGV wrapper that goes through similar operations as hoovahs script, but self creates its inputs and outputs based on the case (enum) you selected from the Xnodes menu item? Would it be worth it? Or do you just transfer the complexity to the scripting environment where the potential for mistakes (and code errors) is more likely and less transparent? Ah. I must have missed that (the deletion). The example just created one ove every enumeration with all controls when I tried it. There are a few directories of this in my temp directory now...lol. I must have opened a slightly older one. I'll take another look to see how you defined that that terminal had to be deleted on that VI. Polymorphic VIs are very useful. I wouldn't throw the baby out with the bathwater. The pros just have to outweigh the cons. Sometimes you don;t need to do a full factorial polymorphic VI if you are just grouping individual functions that already exist into an API. There is no explosion of code then. You ae just consolidating into a single VI for convenience and labeling. It's when you do adapt to type that things get out of hand as it is basically "Save As" then make a tiny change, rinse and repeat N times. Edited July 22, 2015 by ShaunR Quote Link to comment
hooovahh Posted July 22, 2015 Author Report Share Posted July 22, 2015 @ShaunR You make very good points, I think all of which I agree with (is that a first ). Bloat in the LabVIEW can be a very big problem, many massive class and libraries loading all members, and polymorphic VIs loading all members is an issue for sure. In a post on my Variant Repository XNode I mentioned something to this affect, where the polymorphic version has a couple hundred VIs in a couple polymorphic VIs. I certainly wouldn't use this wrapper code for every FGV in my code, it would add unneeded bloat with little (in any) benefit. But there are times when it can make an API easier for the developer to use and understand, by breaking up the possible many functions of an action engine, into easier to understand chunks. Like you said, pros and cons, like with many design choices in software. Quote Link to comment
Neil Pate Posted July 22, 2015 Report Share Posted July 22, 2015 (edited) I kinda like manually adding in the Action Engine wrappers (which I do religiously for FGVs and Action Engines). I create them one at a time and test them out as I flesh out the test harness. Sure, takes a little bit longer (than scripting for example, or using GDS), but it gives my brain time to think about the names chosen for the enum values and the names of the wrapper VIs. Often holes in the API become obvious just when thinking about how the accessors will be used. Edited July 22, 2015 by Neil Pate Quote Link to comment
ShaunR Posted July 25, 2015 Report Share Posted July 25, 2015 (edited) @ShaunR You make very good points, I think all of which I agree with (is that a first ). Bloat in the LabVIEW can be a very big problem, many massive class and libraries loading all members, and polymorphic VIs loading all members is an issue for sure. In a post on my Variant Repository XNode I mentioned something to this affect, where the polymorphic version has a couple hundred VIs in a couple polymorphic VIs. I certainly wouldn't use this wrapper code for every FGV in my code, it would add unneeded bloat with little (in any) benefit. But there are times when it can make an API easier for the developer to use and understand, by breaking up the possible many functions of an action engine, into easier to understand chunks. Like you said, pros and cons, like with many design choices in software. It is something I've said on numerous occasions. Nice someone is finally agreeing with me For example. You can immediately reduce the number of VIs and code size in a LVPOOP project by between [anecdotally] 25% and 50% (50% if its just a small object with only accessors). Only by putting a boolean for get/set rather than using individual VIs for accessors. Oh, wait. We could make it a typdef enum get/set instead of a boolean to make the code more readable. Oh. Now we have an AE......Doh Edited July 25, 2015 by ShaunR 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.