Jump to content

FGVs, Action Engines and DVRs: a rif on Nancy's NI Week presentation


Recommended Posts

I was struck by a number of things at NI Week 2013 but one in particular I want to comment on.  Nancy Hollenbeck did a marvelous job of presenting on FGVs, Action Engines and DVRs.  It was really a great presentation but I did have a thought about one aspect of what she presented.

 

Nancy drew a distinction between FGVs and Action Engines, essentially pointing out that a "bare" FGV is really just a global and, therefore, doesn't protect against race conditions, etc, etc.  From that perspective an Action Engine is an FGV that, because of its "Solitron" like structure does preclude race conditions.  OK, fair enough and clear; however, I had a different thought.

 

FWIW I think we should call a "Nancy" FGV a DGV means a DYSFunctional Global Variable because it has ALL of the liabilities of a global AND is far, far slower to execute.  That would allow us to agree that a FGV is an Action engine BECAUSE it is functional, etc, etc.

 

OK, I do get into semantics at times so I apologize and Nancy it really was a fabulous presentation.

  • Like 1
Link to comment

Semantics aside a FGV can have race conditions, just like a normal global.  But a FGV gives me the ability to perform other functions, other then just read and write.  Because I don't know how my applications needs will change in the future I never use native globals, and only FGV.  Lets say I'm storing an array of values, well I can have my method on the FGV "Read" "Write" and "Average" a native global can't do this without extra code which isn't that big of a deal but I prefer this method.

 

Other functionality that can be done is stuff like WORM.  Where a global can only be written to once then it will generate an error if it is written to again.  Many of the pitfalls of a native global exist in these other VIs, but allowing added functionality, and also adding other debugging tools helps to make sure you don't shoot your self in the foot.  But it can still happen.

  • Like 2
Link to comment

I asked Steven Mercer during his presentation what the difference between a FGV and AE were.  He stated that a FGV was a LV2 global with just a Get and a Set case.  Still trying to figure out how much of that statement I agree with.  But this is something I really wish we all can agree on because I don't like how we mix FGV, AE, and LV2Global all the time.  There really should be a distinction.

Link to comment
I asked Steven Mercer during his presentation what the difference between a FGV and AE were.  He stated that a FGV was a LV2 global with just a Get and a Set case.  Still trying to figure out how much of that statement I agree with.  But this is something I really wish we all can agree on because I don't like how we mix FGV, AE, and LV2Global all the time.  There really should be a distinction.

Agreed. I don't think there is a difference apart from terminology. The get/set FGV is just a problematic corner case AE. I equate AEs with singleton classes rather than global variables and that a LV2Global is the protected storage of an AE just as the private cluster is in a class.

Edited by ShaunR
Link to comment
Agreed. I don't think there is a difference apart from terminology.

 

I disagree.  Here's how I differentiate between them.

 

Normal Global - A data storage container.

Functional Global - A data storage container with get/set methods, allowing the developer to check data validity prior to getting or setting the value.

Action Engine - A functional global that adds methods--other than get/set--to operate on the data.  Essentially when a third method is added to a FG it becomes an AE.

 

I agree there's a lot of fuzziness between FGs and AEs, and my definition is as arbitrary as anyone else's.  I chose that as the defining characteristic because adding methods other than get/set to a FG is taking the first step down a path that easily leads to heavy code debt.  The con pane puts a practical limit on the number of methods an AE can support.  In theory you can jam every possible input and output into clusters and have an infinite number of methods; in practice it makes the AE much harder to use than other implementations.  Restricting the methods to get/set keeps it simple.

  • Like 2
Link to comment
I disagree.  Here's how I differentiate between them.

 

Normal Global - A data storage container.

Functional Global - A data storage container with get/set methods, allowing the developer to check data validity prior to getting or setting the value.

Action Engine - A functional global that adds methods--other than get/set--to operate on the data.  Essentially when a third method is added to a FG it becomes an AE.

 

Well. There is no real difference between FGV and AE from your definition apart from an arbitrary break point to try and make a differentiation.. They both have methods. They both enforce interaction to the internal memory only via those methods  and they both only operate on the data supplied externally to their terminals. It's a bit like saying there is a special name for a class that only has methods and no properties-it's still a class.

 

What about a self incrementing counter that gives you the next value when it is called? That only has a Get method-what is that under your definition?

 

If you really wanted to make a differentiation so as to define a FGV as something different from an AE,, Then you could argue that a FGV does not contain state (only functions and its output is predictable and constant given the inputs), whereas an action engine does contain state and it's output is dependent on the internal state. Under this definition, the Get/Set would be a FGV and the self incrementing counter would be an AE. But I think the number of methods is a bit weak

Edited by ShaunR
Link to comment
The con pane puts a practical limit on the number of methods an AE can support.  In theory you can jam every possible input and output into clusters and have an infinite number of methods; in practice it makes the AE much harder to use than other implementations.  Restricting the methods to get/set keeps it simple.

So I'm sure others have done this too, but when I get this type of AE I will usually wrap the functions into SubVIs so only the important terminals are being shown for that function and then inline the VI.  So maybe Init will call the AE 3 times with different methods and using some but not likely all of the connector pane inputs.  I'm pretty sure I saw this technique on JKI's blog at one point.

 

I agree with your definitions, but I also agree with Shaun that the need for these different terms might not be necessary.  I guess it should be directed to the audience you have.  Some may know what a Functional Global is, and no clue what an AE is (Action Engine for those who don't).  The different terms don't bother me too much because when talking to others about it, it rarely matters what kind of global is being used (as long as it isn't the native one), it just matters that we understand a non-re-entrant VI with uninitialized shift registers is keeping track of some data between calls.

 

Also I'm curious, has anyone developed a tool to perform a search, for a specific VI, where it has an enum constant wired to a terminal, with a specific value wired to it?  I don't think it would be too hard but if I want to find all the places this particular VI has had the "Write Data" method used I either have to find all calls to that VI and look for the constant, or find all places that "Write Data" appears in my code with a string search.

Link to comment
Well. There is no real difference between FGV and AE from your definition apart from an arbitrary break point to try and make a differentiation..

 

Agreed, and I said as much in my post.  The transition from FGV to AE is a variation of the paradox of the heap.  When does FGV become an AE?  When is a heap of sand no longer a heap?  If we're going to make a distinction between FGV and AE (and I think we should since the names convey very different ideas) then we need to choose an arbitrary break point.  I chose that break point because not coding myself into a corner is one of my primary requirements, and adding methods other than get/set is the beginning of that trap.

 

 

So I'm sure others have done this too, but when I get this type of AE I will usually wrap the functions into SubVIs so only the important terminals are being shown for that function and then inline the VI. 

 

...it just matters that we understand a non-re-entrant VI with uninitialized shift registers is keeping track of some data between calls.

 

Once you create a public interface for the AE using wrapper VIs, the fact it is implemented with an AE is irrelevant.  You don't care (or shouldn't care) that the wrappers use a non-reentrant VI internally or that the data is stored on an uninitialized shift register.  You only care that all the public interface VIs refer to the same data and access during read-modify-write operations is controlled correctly.

 

 

Do you guys really use FGV or AE much anymore? I would think it's a dying practice now with native classes.

 

I don't (never did, really) but enough people still use them that it makes sense to understand the differences between them.  (At the very least the discussion gives me some insight into how other developers think.)

  • Like 1
Link to comment

I would take the point that the line is drawn where it is for one reason, so we can express that AE is good and FGV is bad, it is to suit us rather than any actual difference in implementation.

 

I think it might have been Nancy again who also said she saw regional dialects. Developers from one area of the US described them as AEs, other areas were FGVs, others where LV2 Globals. Just depends who teaches you! (Apologies if it was someone else that mentioned this)

Link to comment
Do you guys really use FGV or AE much anymore? I would think it's a dying practice now with native classes.

 

On the contrary, FGV is how one implements static class data. My usage of FGV has perhaps even gone up with the widespread adoption of object oriented design in my LabVIEW code.

Link to comment
Once you create a public interface for the AE using wrapper VIs, the fact it is implemented with an AE is irrelevant.  You don't care (or shouldn't care) that the wrappers use a non-reentrant VI internally or that the data is stored on an uninitialized shift register.  You only care that all the public interface VIs refer to the same data and access during read-modify-write operations is controlled correctly.

I wasn't talking about terminology to public methods VIs, I was trying to say that when in a public forum and discussing FGV vs AE all that matters is that the audience understand what we are talking about.  And by that I mean a uninitialized shift register.

Link to comment

Nancy also mentioned the use of DVRs as a replacement for FGVs and AEs.  There are two ways to make an LVOOP DVR FGV. One is to create a class with methods that operate on the data and then wrap that class in a DVR.  The other is to create a class that has a DVR in its private data and then create methods that create the DVR, access the data in the DVR and destroy the DVR.

My question:

Which one is better?  Which one do you use?

 

One 'feature' she pointed out was if you wrap a class in the DVR, you can wire the DVR to a property node to use the accessors,  This seems cool at first but don't you just introduce the same race conditions that the old get-set FGV had in the first place?  After all, wiring a DVR wrapped class to a 'read' property node is simply a 'get' and wiring it to a 'write' property node is a 'set'.  The operations you do in between are unprotected.

 

Given this, I would argue the the second LVOOP DVR FGV implementation is the better choice.  If you still want to wrap the class in a DVR, simply do not make any 'write' accessors and force the writes to happen in methods that use an inplace structure to protect the data.

Link to comment

I don't believe there is one all encompassing "better" answer to this.

 

This was a question I asked AQ and I often think back to his response. If you have your class API passing a reference then you are making the decision about the scope of access i.e. which functions are "atomic". If you want to call subsequent methods as an atomic operation you can't as each method will get and release the DVR. In this scenario keeping the object by value is better as the developer using the API can decide if he wants to use by ref or by value and can also decide what function calls are atomic and which are not.

 

That said there are often cases where classes only make sense to be reference based. For example I am working on a class for a file API. In this case I use the DVRs in the API as this is how most people would expect a file to work.

 

Thinking about the response from AQ now, I wonder whether the whole property node would be atomic, that would appear to be a sensible implementation although I have never tested it.

  • Like 1
Link to comment
I would take the point that the line is drawn where it is for one reason, so we can express that AE is good and FGV is bad, it is to suit us rather than any actual difference in implementation.

 

That's funny.  I consider FGs an acceptable (though not preferred) way of creating a shared data store or data transport mechanism, while the AE is an ugly hack I always avoid.  (If the goal is singleton behavior, there are simpler ways to get the same behavior that are more extensible.)

 

 

I wasn't talking about terminology to public methods VIs, I was trying to say that when in a public forum and discussing FGV vs AE all that matters is that the audience understand what we are talking about.  And by that I mean a uninitialized shift register.

 

Sure, I understand.  My point is it more useful when names refer to a component's observable characteristics, not according to how it has been implemented.  When discussing a FG vs AE, you're comparing their observable characteristics.  Once you make the AE private and expose its api through wrappers its observable characteristics no longer match what we typically consider an AE; hence, you're no longer comparing a FG and AE.  The component may be implemented using an AE, but it's not an action engine itself.

 

I'll counter with this:  If you mean uninitialized shift register and want the audience to understand what you are talking about, then say uninitialized shift register.  FGs and AEs use USRs in their implementation, but they are not USRs themselves.

 

 

There are two ways to make an LVOOP DVR FGV. One is to create a class with methods that operate on the data and then wrap that class in a DVR.  The other is to create a class that has a DVR in its private data and then create methods that create the DVR, access the data in the DVR and destroy the DVR.

My question:

Which one is better?  Which one do you use?

 

I agree with James that there is no universal "better" answer.  However, I prefer the first solution and believe it is more robust.  To expand a bit on what James said, solution 2 presents some difficulty exposing read-modify-write operations through the public api.  In addition to the normal data access methods, the class has to expose some sort of mutex (lock/unlock) functionality to prevent other threads from overwriting the data between the read and write operations.  The IPE structure is the safest way of mutexing data access; why make it more difficult for users by taking that option away from them?

 

By default all my classes are as by-value as I can reasonably make them.  If I start with a by-val class I can easily create by-ref or singleton behavior by dropping it in a DVR, or global, or whatever.  But, if my class starts out as a by-ref class I can't go backwards and use it someplace where I need a by-val class.  And if it starts out as a singleton, I can't use it as either a by-ref class or a by-val class.  Keeping my core functionality in by-val classes maximizes the ways I can use the functionality the class exposes.

Link to comment

I apologize for not going back and editing my original post but I think everything got the point regardless.  I'd like to add another aspect to this thread: viz, I strongly suspect that the majority of LAVA members who want to keep the FGV|AE distinction "grew up" learning OOP in a CS degree program and most probably with a focus on C++ and/or JAVA.  I didn't.  In fact, I never went to CS courses and I learned to program in PL/1, then onto C and Unix.  I even remember when Linus's Unix (or LI-nix) first came out.

 

So why am I asking about what you "grew up" learning?  Because I think it's exactly on target that the overwhelming majority of LV programmers are domain expert (or domain specialists) and not CS degreed professional programmers.  LV is easy to learn; and, yes, it's easy to learn badly.  So why learn/use (what I'm calling) FGV instead of other solutions?

 

1. There is an extensive "library" of already developed code in the larger LV community based on them.

2. They are clearly dataflow and by-val, unless one violates the encapsulation (as what happens when an originally lean and tight FGV gets "overloaded" inappropriately.

3. They are easier to learn and utilize IF you're a beginning to intermediate LV programmer who is a domain expert/specialist and NOT a programmer who has learned to base their fundamental paradigm around by-ref implementations.

 

Yes, this is LAVA -- so everyone here is presumably "advanced" and, having been programming in LV for more than a decade and doing things with the language that others thought impossible, I believe I'm also advanced; and, perhaps most importantly, I believe that it is critically important to remember the core market of LV.  And that is domain expert/specialist who are NOT CS degreed professional programmers who provide LV (and other language) based implementations for others as their primary business.

 

And, yes, I am strongly considering becoming CLA, primarily so that I can attend the CLA summits.  I only program for myself (my own company) and have no desire to become a LV consultant or wiring business for hire so the CLA as a credential doesn't hold any particular meaning for me, except that it would allow me to fully participate in very interesting discussions!

 

Anyway, sorry to be long winded about this.  Climbing down off the soapbox now so I can have some  :beer_mug:.



Semantics aside...other functionality that can be done is stuff like WORM.  Where a global can only be written to once then it will generate an error if it is written to again.  Many of the pitfalls of a native global exist in these other VIs, but allowing added functionality, and also adding other debugging tools helps to make sure you don't shoot your self in the foot.  But it can still happen.

 

Did uou know that WORM was the original construct that was implemented as CD-Rs? It was originally aimed at being Write Once Read Many as a "real world" persisting physical record that could NEVER be written to again, not just within one instantiation of a running program.

  • Like 1
Link to comment
Do you guys really use FGV or AE much anymore? I would think it's a dying practice now with native classes.

I still find FGV to be a useful tool even in current code. I also am not always working with recent versions of LabVIEW; I'm currently working with a customer with equipment we built in LabVIEW 7 and had one customer several years ago that wanted an update to their LabVIEW 4 code. (The days before undo... :blink: )

Link to comment
I agree with James that there is no universal "better" answer.  However, I prefer the first solution and believe it is more robust.  To expand a bit on what James said, solution 2 presents some difficulty exposing read-modify-write operations through the public api.  In addition to the normal data access methods, the class has to expose some sort of mutex (lock/unlock) functionality to prevent other threads from overwriting the data between the read and write operations.  The IPE structure is the safest way of mutexing data access; why make it more difficult for users by taking that option away from them?

 

By default all my classes are as by-value as I can reasonably make them.  If I start with a by-val class I can easily create by-ref or singleton behavior by dropping it in a DVR, or global, or whatever.  But, if my class starts out as a by-ref class I can't go backwards and use it someplace where I need a by-val class.  And if it starts out as a singleton, I can't use it as either a by-ref class or a by-val class.  Keeping my core functionality in by-val classes maximizes the ways I can use the functionality the class exposes.

 

I don't disagree with this but my point was the use of property nodes to access data in a DVR wrapped class (via their accessors) opens you up to the same race conditions that FGVs (with only get and set operations) have.  So, whenever someone says how cool it is that you can do this, I think 'yeah, but what about read-modify-write issues?'.

Of course you can use the IPE structure to unwrap the class and safely use its methods to modify class data, but that is not using the property nodes.

 

I do use DVR wrapped classes to implement singleton objects, but I am careful to only use the property node feature to read current value and not read-modify-write.

 

I suppose you could pull some tricks to overload the read accessor to modify the data (ex: increment a counter) but I generally would consider that a bad practice.

 

But, if your goal is a "GLOBAL" then that implies 'by-ref' to me and therefore the better choice for replacing a FGV with a class that uses a DVR is to put the DVR in the class private data and protect it with methods for access and modification.  I just don't see the point in making something you intend to be a "GLOBAL" have the ability to be a by-val class.

 

That said, I complete agree that if you are making a class that might be used by-val or by-ref in the future, then wrapping it in the DVR for those by-ref cases is preferable, as long as you keep the property node race issue in mind.

 

Now, if only we could wire a DVR wrapped class into an invoke node to access the class methods, we could do some cool stuff! 

Link to comment

Basically this whole discussion of perceived differences between LV2Global, FGV, Action Engine, or IGV (Intelligent Global Variable) are a bit academic. Traditionally the LV2 style global were the first incarnation of this pattern and indeed in the beginning mostly just with get/set accessor methods. However smart minds soon found the possibiity to also encapsulate additional methods into the LV2 style global without even bothering to find a new name for this. :D

 

In the over 25 years of LabVIEW use new terms have arisen, often more to just have a new term, rather than describe a fundamentally different design pattern. As such these names are in practice quite interchangeable as different people will tend to use different terms for exactly the same thing.

 

Especially the distinction between FGV/IGV and AE feels a bit artificial to me. The claimed advantage of AE's to have no race conditions is simply by discipline of the programmer, both of the implementer as well as the user. There is nowhere an official document stating "AEs shall not have any possibility to create race conditions" and it would be impractical as that would for instance mean to completely disallow any set and get alike method altogether, as otherwise race conditions still can be produced by a lazy user who rather prefers to implement his algorithm to modify data around the AE, rather than move it into a new method inside.

 

I would agree that LV2style globals are a bit of an old name and usually mean the set/get method, but they do not and have not excluded the possibility to add additional methods to it, to make it smarter. For the rest, FGV, IGV, AE and what else has come up, are often used interchangeably by different persons, and I do not see a good cause in trying to force an artificial difference between them.

 

Daklu wrote:

I agree there's a lot of fuzziness between FGs and AEs, and my definition is as arbitrary as anyone else's.  I chose that as the defining characteristic because adding methods other than get/set to a FG is taking the first step down a path that easily leads to heavy code debt.  The con pane puts a practical limit on the number of methods an AE can support.  In theory you can jam every possible input and output into clusters and have an infinite number of methods; in practice it makes the AE much harder to use than other implementations.  Restricting the methods to get/set keeps it simple.

 

Well it is true there is a limit to the conpane, and one rule of thumb I use is that if the FGV/AE requires more than the 12 terminal conpane (that includes the obligatory error clusters and method selector), it has become to unwieldy and the design needs to be reviewed. I realize that many will say, ohh that additional work to refactor such an FGV/AE when this happens and yes it is work, sometimes quite a bit in fact, but it will also in-evidently result in refactoring parts of the project that have themselves become unwieldy. With OOP you can keep adding more and more methods and data to an object until even the creator can't really comprehend it anymore logically, and it still "works". The FGV has a natural limit which I don't tend to hit anymore nowadays and that while my overall applications haven't gotten simpler. :D

 

Michael Avaliotis wrote:

Do you guys really use FGV or AE much anymore? I would think it's a dying practice now with native classes.

You bet I do! :D Haven't digged into LVOOP yet, despite knowing some C++ and quite a bit Java/C#.

 

Daklu wrote:

That's funny.  I consider FGs an acceptable (though not preferred) way of creating a shared data store or data transport mechanism, while the AE is an ugly hack I always avoid.  (If the goal is singleton behavior, there are simpler ways to get the same behavior that are more extensible.)

 

I think it has a lot to do with how your brain is wired. AEs and LVOOP are trying to do similar things in completely contrary ways. I would agree that AE's are not a good solution if you know LVOOP well, but I started with FGV/AEs loooooooong before LVOOP was even a topic that anyone would have thought about. And in that process I went down several times a path that I found to be a dead end, refining the process of creating AE's including to define self imposed rules to keep it all managable for my limited brain capacity. :D

 

They work for me amazingly well and allowed me often to redefine functionality of existing applications by simply extending some AE's. This allowed to keep the modifications localized to a single component and its support functions rather than have to sprinkle around changes throughout the application. The relatively small adaptions in the interface were easily taken care off since the LabVIEW strict datatype paradigm normally pointed out the problematic spots right away. And yes I'm a proponent of making sure that the LabVIEW VIs who make use of a modified component will break in some ways, so one is forced to review those places at least once to see if there is a potential problem with the new addition.

 

A proper OOP design would of course not need that since the object interface is well designed from the start and never will introduce incompatibilities with existing code when it gets extended :P. But while that is the theory I found that in OOP I tend to extend things sometimes, only to find out that certain code that makes use of the object will suddenly break in very subtle and sometimes hard to find ways, while if I had been forced to review all callers at the time I added the extension I would have been much more likely to identify the potential problem.

 

Programming AEs is a fundamentally different (and I certainly won't claim it to be superior) paradigm to LVOOP. I'm aware that it is much less formalized, requires quite some self discipline to use properly, but many of my applications over the years would not have been possible to implement in a performant way without them. And as mentioned a lot of them date from before the time when LVOOP would even have been an option. Should I change to LVOOP? Maybe, but that would require quite a learning curve and maybe more importantly relearning quite a few things that work very well with AE but would be quite a problem with LVOOP.

 

I tend to see it like this: Just like with graphical programming vs. textual programming, some brains have a tendency towards one or the other, partly because of previous experience, partly because of training. I trained my brain over about 20 years in programming AEs. Before I could program the same functionality in LVOOP as I do nowadays in an AE, would require me quite a bit more than weeks. And I still would have to do a lot of LVOOP before I would have found what to do and what to avoid. Maybe one of the problems is that the first time I looked at LVOOP turned out to be a very frustrating experience. For some reasons I can fairly easily accept that LabVIEW crashes on me because of errors I did in an external C component, but I get very upset if it crashes on me because I did some seemingly normal edit operation in the project window or such.

  • Like 2
Link to comment
Before I could program the same functionality in LVOOP as I do nowadays in an AE, would require me quite a bit more than weeks. And I still would have to do a lot of LVOOP before I would have found what to do and what to avoid.

 

Naah. It's just splitting the frames into separate VIs.

 

There is no real practical difference between a class and an AE apart from code bloat :) In fact, many people put classes into polymorphic VIs so they can get back to a single VI (ala an AE ) once they've split out all the functions. If it's warranted, I usually just cut out the middle-man and create the polymorphic VI with a LV2global which solves the many conpane connection problem and gives adapt-to-type as well as a nice selector instead of an enum (and avoiding some of the nasty side effects of adding items to enums).

 

Slightly off-topic. But I've noticed a preference of combo-boxes as selectors instead of enums in LV2013.

Edited by ShaunR
Link to comment
Naah. It's just splitting the frames into separate VIs.

 

There is no real practical difference between a class and an AE apart from code bloat :)

 

That is a somewhat strong simplification! :D

 

Technically you are right, conceptually AE it is a completely upside down way of doing OOP. OOP is about encapsulating the data which the methods can work with while AE is about encapsulating the data AND the methods in one place. The data is always together with the methods which makes things like instantiation a bit problematic. There is also the aforementioned problem of the conpane which is not infinitely expandable. While this is a limit, I haven't found it a limit in the sense that I could not do things I wanted to do. And the side effect is that it makes you think more about extending such an "object". ;) And that is usually always a good thing (except sometimes for project deadlines).

 

As to the code bloat, as soon as you start to do accessor wrappers for the individual AE methods, you go down the same road. :D

 

AEs only work by discipline from the implementor and the user (unless you wrapped them at which point the AE implementation gets a fact that a user should not interest at all anymore). LVOOP works by certain contracts that the development environment and compiler impose on both the implementor and user of the class. You can make a similar point (albeit only in the aspect of implementing one with the other) between C and C++. You can write object oriented code in C just as well but you have no support by the compiler environment for that. Everything beyond the normal C rules has to be done by discipline of the programmer, rather than by the compiler checking that object classes are indeed compatible and can be casted from one to the other class, just to name an example.

 

Also inheritance is a nice feature in OOP, as it allows to easily implement variations on a theme. At the same time, it is also one of the more abused features in many OOP designs. As soon as you find yourself trying to prop a potato class in a car interface, you should realize that you probably have just created a mutant monster that will eventually chase you in your worst nightmares. :lol: Inheritance in an AE context on the other side is simply not feasible.

 

But I would certainly agree that anybody claiming AEs to be generally inferior to classes is simply ignorant. They can be created and used very successfully, if you have your mind properly wrapped around them. I would however hesitate to claim that they are worth to learn at this point instead of LVOOP. As an additional tool in a programmers toolkit they are however still a very valuable and powerful addition to any LabVIEW programmer expertise.

Link to comment

Query: Isn’t it the DVR (or SEQ or other similar reference) that is an alternative to the Action Engine’s uninitialized shift register, rather than LVOOP?   LVOOP is by-value, and you need something by-reference to stand in place of an action engine.  The DVR is by-ref and can be shared among VIs with different con panes, in contrast to the shift register that is constrained to one VI.  

  • Like 1
Link to comment
But I would certainly agree that anybody claiming AEs to be generally inferior to classes is simply ignorant. They can be created and used very successfully, if you have your mind properly wrapped around them. I would however hesitate to claim that they are worth to learn at this point instead of LVOOP. As an additional tool in a programmers toolkit they are however still a very valuable and powerful addition to any LabVIEW programmer expertise.

 

I'm completely on the page with you in most everything you say on this topic; however, I might use the word "prejudiced" instead of, or perhaps in addition to, "ignorant".  One thing I would disagree with is you last point.  IF you come from an OOP background -- eg having grown up in a contemporary CS program, THEN FGVs become an additional tool; however, IF you don't have that background and/or are a domain specialist THEN my strong suggestion would be to begin with FGVs.  They are a much easier starting point given the history of LV and the multitude of legacy examples that are available from a number of sources.

 

If you're not from an OOP background AND you're a domain specialist who just wants to get the bloody thing done, FGVs are the way to go.  In any event, you and I are good examples of that, as are many, many others.

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.