04-18-2012 11:39 AM
Hi,
I'm slowly expanding and learning to use LVOOP in my projects. As such, I don't have true (or rather complete) OO approaches in my projects, rather focusing on replacing little building blocks here and there.
Maybe because of this piece-wise adoptation of LVOOP, I find myself frequently wanting to "wrap" certain objects into either a FGV or a Global (WNRM or WORM style global) to make the object persistent throughout my code.
I'm wondering, is this incredibly bad in general, or is this acceptable for certain use cases?
The problem (to me) seems to be that if I want to do compositions or encapsulate certain behavior into a class, then once I create the object I need to carry the wire around my code less I create a separate (and new memory space) object.. Similar "issues" can be found in traditional LV especially in QSM type applications, where I would never think twice about tossing down a FGV with "initialize" and (default) "get" queue references (and other references) so I didn't have to pull all those ref's around.. Is it deeply frowned upon if I want to do the same with objects?
The case in point I'm dealing with right now is a class that handles reading my application "ini" or configuration information and has methods for returning parameter(s) such as log folder path, last used import folder, location of my (saved to disk) variant index etc. It seemed like such a great idea, since it allows me to grow the interface and functions as needed, while managing all the implementation details inside the privates of the class, right? The problem is I need to either keep re-reading the "ini" file from disk every time I want to access some settings, or I need to keep the object alive by passing the object wire all over the place.
Now, I also have other classes using this class (composition) and if I were to use a FGV type approach to keep the global alive, then I'm suddenly coupling my different classes with non-object code (FGV).. maybe this is just a really bad composition though, I could just as easily require the second class to be "given" the data it needs via a method call rather than an internal call to another class...
I find the OO design and use learning curve at times very steep, but also very rewarding. 🙂 -Just wish I had a good mentor at my work-place that I could bounce questions and ideas off of!
04-18-2012 02:46 PM
and how bad is it to tightly couple classes. Sigh. Could I make it so that I call one class at a higher level first, then pass the parameters in to the other class? -of course. But it would save so much space on the top level if I just called one class from inside the other class, but then they are coupled... gah.. design trade-offs and decissions all the time!
04-19-2012 08:09 AM
Hi Q,
(Should I all you Q?)
I tried to reply yesterday but ....
Yes coupling is one of the issues that come into play but before I touch on that point I'll start out at a high level.
Code written using Action Engines (AEs) can be called "Component Oriented Programming" (COP) (at lest to my very limited self-taught software knowlege).
COP and OOP when realized in LV can be thought of as the inverse of the each other or stated differently, if you turn COP inside out, you have LVOOP.
"What the hell do you mean by inside out?"
With COP we have code that acts on AEs using the methods they expose to act on the data INSIDE the AE.
In LVOOP we point at data outside the method.
So the first obvious advantage of LVOOP is we can use the same methods to act on different data sets simply by passing the methods different wires. To do the same with AEs we need to duplicate the AE. To handle an unknown number of AE at run time using AE, life can get complicated. The same operation is a no-brainer using LVOOP.
But one of the strength of AE is being able to share common data between different threads. This is more complicated in LVOOP since we would have to expose the same wire in multiple threads, which until recently when the DVRs were implemented, could only be done using a sinlge element queue.
SO what you are looking for is "By reference Objects" that can be shared across threads.
So search this site for "By reference" and there are some examples (I think they also ship with LV).
Some of the other topic that go along this idea are "Active Objects" which talk about parallel threads working together (that I think are being called "Worker Pool" and closely associated with that concept is "Messaging" which I think was the topic of the CLA summit. If you are CLA, sign up for the CLA community to see what they figured out.
Now for a warning:
Using AEs in LVOOP seem to introduce coupling that reduces the usefulness of your classes.
Try to avoid using AEs* (In LVOOP classes).
Ben
* Yes, Mr. AE said that.
04-20-2012 09:57 AM
So using the DVR, insted of passing around a lot of data (potentially) by passing (and forking) object wires, you just pass around a wire with a reference to the object.. That still doesn't solve the wiring spagethi that could create.
I'm still looking at examples and reading though so maybe I'll find a way soon, however, I'm still tempted to use a WORM global to store the reference then... (Write Once Read Many). Globals are proven and very efficient (fast) way of sharing global (pardon the pun) data, and the danger with them is race conditions, which if you use them strictly as WORM's is not an issue... This seems to me to be a legit way to pass around DVR references??? -The biggest downside is the straight up implementation does not have a way to force (via compiler) that you stick to the "write ONCE" in WORM other than dilligence by the coder... but right now I can live with that..
Other concerns/comments on passing around the reference using a WORM global?
Thanks!
04-22-2012 04:54 PM
@QFang wrote:
That still doesn't solve the wiring spagethi that could create.
Do you make use of clusters to reduce the number of wires? It's not a good idea to use wireless objects just to avoid wiring spagethi, as there are other ways to organize wires.
04-23-2012 08:31 AM
What I have done (and still do) to carry references is to have an action engine type VI that runs on startup and creates and/or initializes all my queues, notifiers and references (controls/indicators, panes, etc) and keeps them all in a cluster on a shift register in that VI, then wherever I need any reference elsewhere, I just drop the "Get" and grab the reference I need (typically right outside of a while-loop) and initialize the local shift register(s) with what I need at that location. As the last action, I can close all the references (some of them may already be closed elsewhere, particularlily queus or notifiers). This works great for references, but not so much for carrying a single object around, however I liked Ben's pointer to look into DVR's which would allow me to neatly refer to objects using this very same approach that I'm used to from queueus and notifier references, or thats my idea anyway.
Has anyone investigated what performance (memory and/or time) differences there might be between accessing/using an object via DVR reference vs. a Global, particularily for "Write Once, Read Many" WORM type of use? (Other uses of Globals (WMRM) is as we all know not a good idea for so many reasons, so thats not really a relevant use case for the comparison.) My hunch would be that a global may be faster access than the DVR...?
04-23-2012 08:43 AM
No, never did any benchanmarks.
If you are using an AE and putting all of the method calls in cases of the AE, then that should be fast, but cloning the AE will complicate re-use.
If the AE is just holding the class data and AE methods will return the class data, i is a COPY of the data so the data buffer copy will impact performance.
If using a DVR the methods invocation inside inplace structure will operate on the class data INPLACE and will compete with the "All inside the AE" version. The advantage altough is if you need another copy of the class that to support a second widget, you just create an new DVR for the second widget and you are good to go.
Ben
04-23-2012 08:58 AM
Good morning Ben, thanks for your continued eyes on my ramblings, it truely is appreciated, and sure you may call me Q.
I'm not planning on wrapping an object in an AE, just talking references and ways to manage references as far as AE/Objects go, which with your hint about getting an object reference vis DVR is something I can do now.
Also, I find it interesting how you (subconsciously?) keep ignoring my mentions of globals (which are not AE's). . . 😉 They are so stigamtized its kind of funny how they tend to be completely ignored, on purpose or otherwise. I read someplace that a global is about 7 times faster than an equivalent Get or Set operation on a LV2/functional global... 😛
Anyway, at the end of the day, for the use-case that I was originally asking about, I think DVR is the way to go as it lets me keep how I handle my application settings and options internal to an object, while making the settings and options read from file (or generated) globally accessible via a standard interface. Could I do this without LVOOP? Of course I could, in fact I usually used AE's for this type of thing, but I'm working on learning and implementing LVOOP as and where I can to get experiences with what makes good objects and what does not.
If time and curiosity permits, I may also try to look at using a Global instead and see if I can benchmark it somehow, though Ben brings up a good point about inplaceness, though it seems like a global also is "in place"? -not sure how htey are implemented at the low-level.
04-23-2012 09:08 AM
Hi Q,
WHen I can do a "ctrl-e" on a global, I'll concider using them since only then would I be able to "fix" them. Until then...
Review this thread about Globals NOT being faster than an AE. If they can't implement a simple stop flag reliably, I can't afford to waste my time on them.
Inplace globals?
Thats a contradiction in terms. Since every instance of a global may be read at a diferent time, there has to be a buffer to help every instance of the global. How could that possible be "inplace"?
Ben
04-23-2012 09:42 AM
huh.. assumptions and such.. I guess I was mixing how I figured a global was working (which was pretty much like a pointer in C, hence the problem with race conditions) vs how it really is implemented (still black box). If it was a pointer like implementation, I figured it would be 'in place" as in all data read and writes are done on one copy in memory, or "in place", without it ever being copied.
Globals in LabVIEW I'm now more informed. 🙂
I looked for the "7 times faster" thread, but can't find it at the moment... so I can't substantiate my claim at this point.
I read parts of your linked post, and have re-adopted my life-long avoidance of Globals. I'm now walking down the DVR path for now to see where that leads me.