LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Global Variables Are Better than Functional Globals - So There! :-)

Solved!
Go to solution

I am feeling a little controversial today so forgive the blunt title of this post Smiley Very Happy

 

I have never used global variables because I was under the misconception that they are somehow "bad". That is all I have heard from the time I started learning LabVIEW. Look at code in the upconvert and downconvert threads. Some of the ugliest code uses globals and some of the most beautiful code does not. This implies that bad programmers use global variables and therefore globals are bad programming practice. This is not true. Globals are just easy to use so beginners use them. "Uninitialized what? I can't find those on the pallette?"

 

I think I always subconsciously questioned that globals are bad. They are not bad it is how they are used that can be bad. This is true of anything in life.

 

The first and most obvious problem with global variables is race conditions. But it is not strictly the global that causes the race condition. It is the undefined dataflow.

 

global-race.PNG

 

But the same is true of a functional global if used incorrectly. In the example below there is nothing to enforce dataflow.

 

fgrace.PNG

 

You need to enforce the dataflow with an error wire for example.

 

fgnorace.PNG

 

Globals do not have an error wire but not to fear - the sequence man is here!

global.PNG

 

You only need the sequence if the global is directly on your block diagram. Those two single frame sequence structures could be replaced with a NumericWrite.vi and a NumericRead.vi containing nothing but the global, a control or indicator respectively, and the error terminals. Set them to inline and you are good as gold. Or you could have one subvi containing nothing but a two frame case structure selected by an enum containing the items "Get" and "Set". It now looks like a duck and quacks like a duck. Don't worry about overhead from the case structure either. If the enum is a constant it will be folded out.

 

Another problem with globals is that they are, well, global. This is no different from a functional global so it is not really an issue anyway. For both globals and functional globals this is easily addressed by placing them in a library and setting the access scope. Besides that libraries give you namespaces and "Namespaces are one honking great idea -- let's do more of those!" *

 

The real reason to use a global instead of a functional global is that they are about twice as fast.

 

Up until this morning I would have recommended to use a functional global over a global. But I changed my mind. Can anyone change it back? Smiley Very Happy

 

 

* The Zen Of Python

=====================
LabVIEW 2012


Message 1 of 51
(17,078 Views)

That makes sense to put the sequence structures around the global variables, but couldn't it get more complex? After all, globals are used to transfer data between SubVIs, and I think data flow can get more complex when you have VIs in parallel than globals in series. I do use global variables in some of my code, but only to transfer data from one VI to another parallel VI. In this application I have only one global that writes and many that read. 

 

As for functional global vs. global, I have always used globals, so I'm not sure if they are really better or not. Why would a person ever use a functional global variable? They seem more complex to me, so I've always avoided them.

0 Kudos
Message 2 of 51
(17,054 Views)

You pretty much cover the benefits of globals pretty well. The most severe race condition I faced (SW was delivered and running for 3 month), I did fix by using a sequence around the global. They are so easy to code, so why not? I use them for global hardcoded configs that are set in the init routine of the main program to adress specific customers requests.

Also, because of the speed, they are recommended for look-up tables and related.

 

But as you requested to 'change your mind back':

Scalability!

Once you need some code to make it working properly/faster/better, the simple global doesn't work. Any functional global could be changed to an AE to go full-power. Consider the following scenarios (brainstorming order):

* Apply limit checking, so only certain values are allowed

* The very high-performance data operations on large data sets (Ben is a the master of this stuff, I've never done this), where you can use some inplaceness of the data on the USR (like replace array element)

* Use auto-initialization (e.g. read from config file) using the first call prim (my favourite)

* AEs/FGVs can be distributed via VI Server (again I'm just referring to posts of Ben)

* Following the idea of OOP, I'd like to put together the data (FGV) and the methods that operate on that data (AE). So e.g. in many cases there is also a Save and a Load case apart from Get/Set.

 

Getting further, we need to realize the AEs are in most situations now 'replacable' by LVOOP, and those extra-powers again do us a lot of favors.

 

I think the really-really bad thing about globals is, they are named global variables. So the beginner (with some or even expert knownledge of other programming languages) tends to use them instead of wires.

 

Felix

Message 3 of 51
(17,040 Views)

@zenthoef wrote:

That makes sense to put the sequence structures around the global variables, but couldn't it get more complex? After all, globals are used to transfer data between SubVIs, and I think data flow can get more complex when you have VIs in parallel than globals in series. I do use global variables in some of my code, but only to transfer data from one VI to another parallel VI. In this application I have only one global that writes and many that read. 

 

As for functional global vs. global, I have always used globals, so I'm not sure if they are really better or not. Why would a person ever use a functional global variable? They seem more complex to me, so I've always avoided them.


The point of the sequence structure is to illustrate the cause of race conditions. This also applies to local variables but that is another topic. I still suggest not to use locals unless you have to update the value of a control.

 

It is not the variable itself that causes race conditions. If you have one instance of a global in a.vi and one instance in b.vi then you do not have a race condition and do not need the sequence structure.

 

The only time you would want to use a functional global instead of a global is if you want to do some kind of action on the data. But then it is an action engine - a type of functional global.

=====================
LabVIEW 2012


0 Kudos
Message 4 of 51
(17,037 Views)

Felix, good point about scalability. I was refering to just storing and retrieving data. But "you never know". That is why I posted this on the idea exchange this morning. Aristos's comments prompted this post.

 

I will get the duct tape ready for when Ben chimes in on the second point.

 

If the global is in a subvi couldn't you still use the first-call for auto-initialization? Same for distributing via VI Server. If the global is in a subvi wouldn't that still work? I have never used a global variable but I have inherited code that does.

 

I am using OOP more and more. It is almost an instinct to use that anytime I find myself wanting to create an Action Engine.

 

And finally yes it is very unfortunate that these things are called variables. That was (in my opinion) a big mistake that NI made early on. I like the term "wire" but they probably should have been called "variables". But that would be pretty strange.

 

So your points are well taken. But for the question of global vs. simple FG with only "Set" and "Get" I still think the global vi is faster and simpler and therefore "better".

=====================
LabVIEW 2012


0 Kudos
Message 6 of 51
(17,024 Views)

I would argue that globals are bad for another very important reason. They couple your code together and are a lazy way to design an interface between objects/subVIs. If you approach the code design from a programmer's perspective you want to design your objects/modules to be reusable and essentially self contained. That is, you don't want them to need to know about other parts of the system they are being used in. In addition, your application should not have to know about the internal workings of your subVIs or objects. Using a more LVOOP approach (and you don't have to actually use objects to do this) you should create well defined interfaces for your modules. Access the modules through those APIs. Using globals makes both the modules and the application dependent on on another. You can't easily replace the modules nor can you easily reuse them.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
Message 7 of 51
(17,009 Views)

If the global is in a subvi couldn't you still use the first-call for auto-initialization? Same for distributing via VI Server. If the global is in a subvi wouldn't that still work? I have never used a global variable but I have inherited code that does.

 

If the global is in a SubVI, you can make this an AE with all the powers. You just also need to make it a library and prevent anyone from using the global by making it private (acess scope is a major draw-back of globals before the libraries). And your performance benefits are gone (SubVI overhead) + you can't use the inplaceness of the USR.

 

If you inherite code, leave them until you need to do something different with it. I found it more troubling to to move to a FGV from a tested global without any reason to refactor that code.

 

I am using OOP more and more. It is almost an instinct to use that anytime I find myself wanting to create an Action Engine.

 

If you need max performance, remember AEs (and ask Ben 😉 ). If you don't need inheritance, an AE does the same. Difference is you don't have a wire for the object and you always have exactly the same ConPane for all methods.


So your points are well taken. But for the question of global vs. simple FG with only "Set" and "Get" I still think the global vi is faster and simpler and therefore "better".

 

If we just talk about an enum or a boolean flag, who cares about speed...Speed is of major concern when using large data sets, and in this case I'd use an AE, because of the inplaceness already mentioned. Sure there are situations where you need to access the full data set (look-up tables), in this situation the global wins.

Second, my own benchmarking (somewhere on LAVA about buffer reuse) has shown me a huge difference depending on the LV version used. So if speed matters, I'd always benchmark on the target system (I once developed code in Delphi that ran faster when executed on a single core). Same as OOP, you can do some tricks by putting data in a SEQ or the like and see if the compiler makes it run faster.

 

Felix

0 Kudos
Message 8 of 51
(16,998 Views)

 


@Mark Yedinak wrote:

I would argue that globals are bad for another very important reason. They couple your code together and are a lazy way to design an interface between objects/subVIs.


 

I totally agree and would never recommend using a global or even a functional global as the interface to a module. But that is outside the scope of what I was getting at. Globals in and of themselves are not the problem.

 

I have created standard action engines with an enum containing items for various functions. The AE and enum is scoped private to the library. For each of the functions I will create a public wrapper vi around the private AE. The enum is a constant inside the wrapper. The wrappers are called things like "Initialize", "Calibrate", "Measure", "Log Data", "Close", etc. Nice because the wrappers can have their own icons and connector panes. That was before I started using LVOOP.

 

The same could be done with a global vi. The library could have public wrappers around the private global.

 

 

=====================
LabVIEW 2012


0 Kudos
Message 9 of 51
(16,974 Views)

 


@zenthoef wrote:

After all, globals are used to transfer data between SubVIs,

 


 

No... Wires are used to transfer data between sub-vi's (or main to sub-vis).

 

Felix explained it very well, so no need to repeat what he was saying..

 

There is nothing wrong with Globals or Locals for that matter, but they do get abused and that's what's wrong with them.  People treat Locals and Globals as the variable.  The variable is the wire.  Nothing else.  So cloning the wire all the time is not a good idea...

 

And I agree with Felix on the topic of scalability.  FG's are easy.  And they can also be abused, just like anything in any programming language.  What is important is to know what to use, where & when.  Unfortunately, as seen in many places, people don't pay much attention to that (what to use, where & when) in order to avoid various issues...  Kudos to Felix!

Message 10 of 51
(16,964 Views)