LabVIEW Development Best Practices Documents

cancel
Showing results for 
Search instead for 
Did you mean: 

Factory Pattern

 

(adapted from Gang of Four’s Factory pattern)

Intent

Provide a way to initialize the value on a parent wire with data from many different child classes based on some input value, such as a selector ring value, enum, or string input. This may include dynamically loading new child classes into memory. Ideally new child classes can be created and used without editing the framework.


Motivation
Data comes from many sources – user interface, network connection, hardware – in a raw form. This data frequently comes in types, and the data is to be handled generically but each type has a specific behavior at the core of the handling. Such a problem cries out for the use of classes and dynamic dispatching. We want to write an algorithm around some common parent type and then let dynamic dispatching choose the correct subVI implementation for the parts of the algorithm that are type specific. The hard part is in initializing the right class from the input data.

 

Implementation

Any application using LabVIEW classes generally has a framework that is written using the parent class, and then at run time, child classes travel on the wires through the framework. This pattern provides a mechanism for dynamically selecting the child classes, including dynamically loading them into memory after the program starts running, if necessary.

 

The basic idea is this: Use some bit of data to identify the path to the class you are interested in loading. Use the Get LV Class Default Instance.vi function to load the class into memory and get an instance of that class.

 

Once you have used the factory to get a particular class of data, you are free to use it as you would any other class. Commonly, you would wire the chosen class instance to an Init method of the class which would take your data as an input. The advantage of this system is that the child class is only loaded into memory if someone actually wants to instantiate that child. If you have a great many possible types of data, this can save on memory and load time for your application. The name of this pattern comes from the fact that a single VI serves as a factory to produce all the myriad child types.

 

Once loaded into memory, a class will stay in memory as long as its parent class is running or there are any objects of that class type still in memory. Since objects can lurk all over the place – as the operate value of controls and indicators, as the last value in an uninitialized shift register, etc – it is basically impossible to dynamically unload a class once it is loaded. You should not attempt any architecture that is predicated on being able to unload and reload a class.

 

Editorial Comments

 

[Stephen Mercer] An example of this pattern was made available by Christina Rogers in her refactoring of the Getting Started Window in the Init From XML methods. Information about this example is available here:

Note that her example predates the introduction of Get LV Class Default Instance.vi. She used a method for loading classes into memory that works fine, but only works in the development environment, not in the runtime engine.

 

[Michael Aivaliotis]

Other Example (VI Shots):

Elijah Kerry
Chief Product Manager, Software Platform
_______________________________________________
Follow my Software Engineering for LabVIEW Blog
Comments
Member vishots.com
Member

Will it be possible to unload classes in future versions of LabVIEW?

David S.
NI Employee

You can do that now: since an object wire is treated the same way as any other by the LV garbage collector, you can just not pass it out of the VI that created it and let that VI go idle without its front panel showing. Have you read the excellent LabVIEW Performance and Memory Management document yet?

I don't know what R&D's plans are for LabVIEW, but as it's been a managed language for the last 20+ years, I suspect things will stay the same for the foreseeable future.

David Staab, CLA
Staff Systems Engineer
National Instruments
Proven Zealot
Proven Zealot

I'm not sure what David S is referring to, but my answer is, "No."  My guess is that David S is referring to memory disposal of *objects*, where as Michael is asking about unloading of *classes*.

A class cannot leave memory until all objects of that data type have left memory. You might think that would mean that a class could leave memory as soon as we hit zero instances of the class. Two problems. The first is that in practice, after a class is instantiated, it is hard to get the instances back down to zero -- any terminal retains the value from its previous execution until overwritten on the next call, which means that guaranteeing that all the copies are gone is very hard for a LV user. But let's assume that a really assiduous user does find a way to clear all the instances -- that brings us to the second problem. It is perfectly legit for there to be zero instances in memory and a moment later to have an Unflatten From String or similar function try to instantiate that class. If we detected that we hit zero and started the unload process, we would need to block all other parallel operations that are capable of instantiating data so that they didn't try to instantiate data while we were midway through tearing down the class. That would introduce mutexes into operations that we do not want to have mutexes. The thread friction would be too high for other operations that are instantiating data that doesn't involve classes, and on RT, even involving classes would be a hit we want to avoid.

Therefore, once a class is loaded into a running VI hierarchy, it never gets to leave memory until the VI hierarchy goes idle AND there are zero instances of the class left in memory. In practice, this means that most developers have to assume that "once loaded, always loaded" is generally true.

David S.
NI Employee

Yes, I was talking about objects, because in all the texts I've read, a class is just a description of an object and can't be directly instantiated and manipulated as a data item in memory. But then I don't write compilers for a living.

David Staab, CLA
Staff Systems Engineer
National Instruments
Knight of NI Knight of NI
Knight of NI

Thanks Aristos!

I have run into the issue of unloading.

What recomendations if any do you have for the situation where we want to deallocate the memory buffers allocated to a class wire that is no longer used.

In my case I dynamically loaded VIs based on a Generic Class. I could load 100 instances of those VIs and ran fine. But If I closed all of those dynamics, and turned around and tried to launch another set of 100 based on a sibling (Same parent class) would run out of memory.

The top-level app that did the loading did have a copy of every possible Class (loaded by serach for compatable calsses on disk) so I understood my issue as being due to that fact.

So I realize i am reaching for a very fine razor but I just want my memory back, and am looking for ways to get it.

Ben

Member vishots.com
Member

Ben: [dynamically loaded VIs based on a Generic Class]. Do you mean dynamic dispatch? Or using the Run VI method?

Aristos: So just to clarify this.

  1. I create an object of class-A (using the factory pattern) and populate it with data.
  2. I dynanically run an accessor VI of class-A (using the Run VI method).
  3. I then let the accessor VI go idle. No other direct calls to class-A object exist.

My understanding is that the Accessor VI will stay in memory since Class-A is loaded and cannot be removed from memory. However, the object data (used by the accessor VI) will be removed from memory.

Member mavimi
Member

Link for the Eyes On VIs blog in the editorial comment is broken. New link:

http://www.eyesonvis.com/blog/2006/08/object-oriented-getting-started-window.html

Member monzue
Member

I would like to point out another example program that has an implementation of the factory Pattern.

https://decibel.ni.com/content/docs/DOC-15682

and I would also like to put emphasis on this fact shown in the image below:

you may want to cast the Object class out of Get LV Class Default Value and use the "Oldest" class reference that you need.  Information about the specific class is there and will be used "down the line" to load the correct dynamic dispatch vi.

parent class example.PNG

It may seem simple, but I missed this fact until now as I am gradually learning LVOOP.

Ben Yeske 

Ben Yeske
Member AmitKaria2k
Member

I am using factory pattern for its advantage of loading classes only a single calss into memory when needed.

I saw LabVIEW example on http://files.vishots.com/wp-content/uploads/2011/04/VISV-005-Code.zip as well as a short video of this on http://vishots.com/005-visv-labview-class-factory-pattern/

I opened the project from above example (Note: I haven't still opened Main UI (Dynamic class loading).vi). Now, if I see LabVIEW Class Hierarchy window and VI Hierarchy window I'm able to see all the classes and Sub VI's loaded into memory.

I'm not able to understand this behaviour.

I would appreciate if someone can take a look in to this.

Thanks

Amit Karia

Proven Zealot
Proven Zealot

A project loads all the classes listed in the project. You'll have to open the VI without opening the project.

Member AmitKaria2k
Member

Great.. Thanks !!

Member jfalesi
Member

Great writeup.  Just a nit-pick on this phrase:

"Such a problem cries out for the use of classes and dynamic dispatching".

I think this should read "Such a problem cries out for polymorphism."  If I'm not mistaken, classes and DD are simply parts of LV's implementation of polymorphism, just as inheritence and dynamic binding are part of C++'s implementation of polymorphism.  For that matter, it seems that dynamic dispatching is just another name for dynamic binding.  Am I missing something?

Nit-picks not withstanding, I am in love with the idea of dynamic class loading and am about to attempt to implement it in my first LVOOP project.

Thanks,

-Jamie

Proven Zealot
Proven Zealot

jfalesi:

Yes, you're right. And you're wrong. And it all depends upon your point of view. :-)

Both of these terms "polymorphism" and "dynamic binding" are generic CS terms for various things that you could do in a programming environment, but what they mean in any particular programming environment is totally undefined. Every language uses these terms in different ways because each language ends up with very different IDEs, parser logic and runtime capabilities.

We try to use terms that are recognizable to LabVIEW users in our writeups. In the LV context,  "Polymorphism" would mean PolyVIs to many users, which would be misleading. At best "polymorphism" is a way too ambiguous term to be useful since it just means "allowing your call site to adapt to your parameters" and I and many others generally think of that as only occuring at compile time whereas dynamic dispatching is at runtime. Now, you can call that "runtime polymorphism," but there are many flavors of that as well.

As for "dynamic binding," that would be the wrong term for one of two reasons depending upon which definition of dynamic binding you use. Either

a) All subVIs in LabVIEW are dynamically bound since LabVIEW does linking at load time, so, no, dynamic dispatch is not particular to dynamic binding

or

b) Dynamic binding would be if you didn't even know what method was going to be called until runtime.

In this case, we're calling attention to the specific LabVIEW technology that addresses this problem, which is dynamic dispatching.

Does that makes sense?

Member jfalesi
Member

Sort of... I get the potential confusion with polymorphic VIs but I don't get the rest of your explanation. I've never understood polymorphism as a compile-time thing, but I guess that's because my reference point is C++/Java/Python (which I believe are all "runtime-polymorphic" languages).

What do you mean by "LabVIEW does linking at load time"? Do you mean when I load my LabVIEW project/VI? My confusion probably stems from not understanding how LV works. When does LV compile code? I assume that it compiles continuously every time a change is made, based on the observation that syntax errors are pointed out in real-time (i.e. broken wires). If so, then LV compiles at load time, thus load time = compile time, which means that regular VIs are statically bound (at least according to the Wikipedia definition). Thus, I don't understand (a). As for (b), this seems to be the definition I am using for dynamic binding. Using this definition, I still don't understand how this is different than what LV does. Whether I'm writing LV code or C++ code, I thought the whole point of "late binding" is to allow your code to compile even if it is not known precisely which methods are called, and in fact to look up methods and "bind" them to calls at run-time.

Perhaps we're talking past each other...

Either way, I'm thrilled that LV allows OO programming regardless of the terminology and specific technology. I'm glad there are people who understand computer languages enough to implement whatever technologies make it work

Question: If I'm interested mainly in reducing run-time latency, would I be better off not using dynamic class loading? My app needs to stream data via TCP/IP in real-time.

Thanks,

-Jamie

Date: Tue, 9 Dec 2014 17:45:19 -0600

From: web.community@ni.com

To: jfalesi@hotmail.com

Subject: Re: - Factory Pattern

Community

Factory Pattern

new comment by AristosQueue View all comments on this document

jfalesi:

Yes, you're right. And you're wrong. And it all depends upon your point of view.

Both of these terms "polymorphism" and "dynamic binding" are generic CS terms for various things that you could do in a programming environment, but what they mean in any particular programming environment is totally undefined. Every language uses these terms in different ways because each language ends up with very different IDEs, parser logic and runtime capabilities.

We try to use terms that are recognizable to LabVIEW users in our writeups. In the LV context, "Polymorphism" would mean PolyVIs to many users, which would be misleading. At best "polymorphism" is a way too ambiguous term to be useful since it just means "allowing your call site to adapt to your parameters" and I and many others generally think of that as only occuring at compile time whereas dynamic dispatching is at runtime. Now, you can call that "runtime polymorphism," but there are many flavors of that as well.

As for "dynamic binding," that would be the wrong term for one of two reasons depending upon which definition of dynamic binding you use. Either

a) All subVIs in LabVIEW are dynamically bound since LabVIEW does linking at load time, so, no, dynamic dispatch is not particular to dynamic binding

or

b) Dynamic binding would be if you didn't even know what method was going to be called until runtime.

In this case, we're calling attention to the specific LabVIEW technology that addresses this problem, which is dynamic dispatching.

Does that makes sense?

Reply to this email to respond to AristosQueue's comment.

Proven Zealot Proven Zealot
Proven Zealot

I personally wouldn't consider C++ or Java as runtime polymorphistic. Sure you can have the same object method name several times with different parameter types, which is in some ways similar to LabVIEW Poly VIs, but that is compile time polymorphisme, not at runtime. And you can of course use the nasty void* pointer but that goes at the cost of any and all type checking at compile time. And then you can pass object variables but that is also not polymorphisme.

As to dynamic binding that is exactly what LabVIEW does, much like what is done when you use dynamic link libraries. Basically each VI results in an object code resource that gets linked through some dispatch tables on load time of the hierarchy.

As to compiling: No LabVIEW doesn't completely compile the code at every edit step. That would be to costly and useless. Instead it separates the compile stage into a syntax check stage where the directed graph that the diagram represents is checked for any inconsistencies. Once you save the VI, or run it or force recompilation, LabVIEW then creates the actual intermediate DFIR which is then passed to the LLVM compiler to be turned into the final machine object code resource. This code resource is stored for each VI individually with indirect calls to other VIs through dispatch tables. This dispatch tables are then patched up on loading of the VI hierarchy according to the name of the VI, very much like how dynamic link libraries are linked to.

But this dynamic linking is pretty much static as the association between the caller and callee is done based on name at compile time. This is like how you reference to DLL funtions through static import libraries, not like calling LoadLibrary() and GetProcAddress() on your own at runtime.

Dynamic dispatch in LVOOP is quite different since the actual dispatch table is determined at runtime.

But I agree with Aristos. Naming is a tricky business and assumptions in respect to one language have often little or no meaning in respect to another language.

Rolf Kalbermatter
Averna BV
LabVIEW ArchitectLabVIEW ChampionLabVIEW Instructor
Proven Zealot
Proven Zealot

jfalesi wrote:

Question: If I'm interested mainly in reducing run-time latency, would I be better off not using dynamic class loading?  My app needs to stream data via TCP/IP in real-time.


                   

That's really not an answerable question without examining your application directly.

Dynamic loading occurs once for each type. It's a rare event regardless of your code. Is your stream a homogenous stream that only needs dynamic loading for the first packet and all packets thereafter use the same type? Or is it a heterogenous stream that may need to load additional classes later? If it is a heterogenous stream, even then, dynamic loading may not screw up your real time processing -- remember, real time just means on a defined schedule. You may have enough slack in your schedule to load more classes. Or you may have the ability to handle a periodic schedule miss without falling behind. You'll have to do your own benchmarks to determine if any given architecture meets your requirements. And you'll have to figure out whether any other architecture you pick will just run into the same problem through another means.

Proven Zealot
Proven Zealot

jfalesi wrote:

If so, then LV compiles at load time, thus load time = compile time, which means that regular VIs are statically bound (at least according to the Wikipedia definition)


                   

Compile time of an individual VI is not the same as compile time of an entire C++ program. In C++, all functions are compiled AND LINKED together to produce a single exe/dll. In LabVIEW, on the desktop (FPGA is different), each function is compiled on its own, with a few exceptions for inlined subVIs and the like. We don't do linking until load time, even in an exe or dll, although we might change that. Moreover, for any reentrant VI, we definitely don't link until run time -- preallocated clones link at the start of a program run, shared clones relink everytime a subVI call is made.

All of this is behind the scenes details that are subject to change at the whim of our compile team. We don't describe features of LabVIEW in terms of what is happening behind the scenes because we can (and have) changed that implementation to maximize the efficiency and utility of LabVIEW applications.

Member jfalesi
Member

Thanks for your input, Aristos.  Do you have any recommendations for tools or methodologies for real-time benchmarking?  I'm a total n00b to real-time.

Thanks,

-Jamie

Member Ficare
Member

Je serai absent(e) à partir du 20/12/2014 de retour le 05/01/2015.

Member MathieuG
Member

I have an issue with the Factory pattern once my app is compiled.

Let's consider an example:

- I save an array of Measurement objects (MeasurementA.lvclass, MeasurementB.lvclass, ...) in a config.xml file when I close my app (I use the labview 'Flatten to XML' and 'Write to XML file' functions).

- I enclose the lvclass-files in the binary (using the 'Source Files>Always Included' setting of the build specification)

- When being reopened the compiled app should load back the array of Measurements objects from the xml file.

- For this to work, the involved classes should already be loaded in memory.

- I do *not* want to load all Measurement classes statically and would rather prefer a solution based on the factory pattern

The XML file only save the name of the lvclass files, not their paths. I could not find a way to list the lvclass files available within the binary file: How should I proceed?

I am using LabVIEW 2014 SP1 and 2015 SP1 but I could drop LV2014SP1 altogether.

Active Participant andre.buurman@carya
Active Participant

Hello Mathieu,

We have the same issue, you need to somehow create a static link to at least the one object per child class.

We do this by dropping a class constants Vi in the main VI of our applications and the used the pre-build VI to dynamically fill it with 1 instance of each class in our project. This way all classes are included in the built application.

Hope it helps,

Regards,

André

Regards,
André (CLA, CLED)
Member MathieuG
Member

Hi André,

used the pre-build VI to dynamically fill it with 1 instance of each class in our project

if I understand you right, you define the classes to be loaded at compile time (pre-build)? I guess you have more than one build specification then.

I only have one build specification and what I would like to have is a mechanism to load only the classes required at run time (much less classes than what is available and potentially loaded later on as the program is being used).

Active Participant andre.buurman@carya
Active Participant

I use the Pre/Post Build Actions (Execute VI before build).

In that VI we have added some scripting that fills the constants VI with the required classes.

We have a single build specification. LV child classes are not part of the build in case your block diagram only has parent wires. That's why we add them to a constants VI. We add the classes automatically to constants VI use the Pre Build Action. (to make sure a new child class is always added to the build).

Regards,
André (CLA, CLED)
Contributors