Avoiding Global Variables

How to avoid using global variables?

One could ask what reasons you might have to structure your code like this, but assuming you have your reasons, you could just return the values from your secondary function:

def secondary_function():

alfa = 12
beta = 5

if alfa > 10:
alfa_is_higher_than_12 = "yes"
else:
alfa_is_higher_than_12 = "no"

if beta > 10:
beta_is_higher_than_12 = "yes"
else:
beta_is_higher_than_12 = "no"

return alfa_is_higher_than_12, beta_is_higher_than_12

def main_function():

alfa_is_higher_than_12, beta_is_higher_than_12 = secondary_function()

if alfa_is_higher_than_12=="yes":
print("alfa is higher than 12")
else:
print("alfa isn't higher than 12")

if beta_is_higher_than_12=="yes":
print("beta is higher than 12")
else:
print("beta isn't higher thant 12")

How do you avoid using global variables in inherently stateful programs?

Typically, this kind of problem is handled by passing around a shared context:

graphics_api.h

#ifndef GRAPHICS_API
#define GRAPHICS_API

typedef void *HANDLE;

HANDLE init_graphics(void);
void destroy_graphics(HANDLE handle);
void use_graphics(HANDLE handle);

#endif

graphics.c

#include <stdio.h>
#include <stdlib.h>
#include "graphics_api.h"

typedef struct {
int width;
int height;
} CONTEXT;

HANDLE init_graphics(void) {
CONTEXT *result = malloc(sizeof(CONTEXT));
if (result) {
result->width = 640;
result->height = 480;
}
return (HANDLE) result;
}

void destroy_graphics(HANDLE handle) {
CONTEXT *context = (CONTEXT *) handle;
if (context) {
free(context);
}
}

void use_graphics(HANDLE handle) {
CONTEXT *context = (CONTEXT *) handle;
if (context) {
printf("width = %5d\n", context->width);
printf("height = %5d\n", context->height);
}
}

main.c

#include <stdio.h>
#include "graphics_api.h"

int main(void) {
HANDLE handle = init_graphics();
if (handle) {
use_graphics(handle);
destroy_graphics(handle);
}
return 0;
}

Output

width  =   640
height = 480

Hiding the details of the context by using a void pointer prevents the user from changing the data contained within the memory to which it points.

Should global variables in javascript be always avoided?

so the reason for to avoid using global variables as much as possible as stated in the previous answers. It is about easily overriding problem and troubleshooting when some global values are being overriden. From my own experience, I usually create an utility to handle sharing values. The idea is as following

//global.js
(function(){
const context = {};
function setGlobalValue(key, value) {
context[key] = value;
}
function getGlobalValue(key) {
return context[key];
}
window.setGlobalValue = setGlobalValue;
window.getGlobalValue = getGlobalValue;
}());
// app.js
function codeAddress(address) {
geocoder.geocode({ 'address': address},
function(response, status) {
if (status == 'OK')
{
var senddata = $.get('/myurl',{params}, function (data){ setGlobalValue('codeAddress', data) });
} else {
}
});
}
// get value here
console.log(getGlobalValue('codeAddress'));

by this way we can track all the global values by searching for setGlobalValue since this is the only way to set "global" value context.

How to avoid using a global variable?

You could put all your functions inside a class, and make the "global" variable an attribute. In that way you can share it between methods:

class Player(object):
def __init__(self):
self.paused = False
def play_music(self):
if not self.paused:
# and so on
def pause_music(self):
if not self.paused:
# etc.

Is this strategy, to avoid global variables in C, right?

There are several questions in there:

is this a good approach?

Yes. There is perhaps an argument for placing the ISR in the same module as the access functions and data it shares, treating it as an access function itself allowing it to read the data directly without the access wrapper overhead.


Is it better/worse/equal to simply have a bunch of globals?

Much worse. With a global where are you going to place your access mutex, data validation or breakpoints? It increases module coupling, and that should always be minimised.


Any major drawbacks?

Not really. There is a function call overhead which may be critical in an ISR; but if that were an issue you would not be calling printf() in an ISR! You can mitigate any possible performance penalty applying my earlier suggestion about placing the ISR in the data module, or by in-lining the code - but your compiler is free to ignore that, and may do so if debugging is enabled, and may also inline regardless if optimisation is enabled. Some compilers have a "forced" inline extension that the compiler is not allowed to ignore; but it is not portable.

One significant benefit is that if the variable is non-atomic, you need some access protection mechanism to ensure consistent access - and that is most easily and safely performed by having access functions. In this case you might have get / set functions that disable and re-enable the interrupt around the access for example, or use a spin-lock (suitable for where the ISR writes and the normal context reads - not the other way around as you have here - don't lock the ISR indefinitely!) .


I also thought I could use some sort of mix like still having the global variables to allow direct manipulation by the ISR (since function calls from the ISR are sometimes frown upon) and the functions in every other case. Would this be better?

Not really - see my point above about function call overhead and placement of the ISR with the data. The problem with calling functions in an ISR is seldom a time-overhead issue, but rather that the implementer of the function may not have designed it to be called safely and efficiently from an ISR and it may use excessive stack, non-deterministic execution time, busy-wait or not be re-entrant or thread-safe. Calling third-party or standard library functions for example may be ill-advised; calling functions you have specifically written and designed for the purpose and conforming to your specific constraints is not necessarily a problem.


All you need to know about why globals are a bad idea and appropriate ways to avoid them can be found in Jack Ganssle's article "A Pox on Globals" - it is also an entertaining read.

The best way to avoid using lots of global variables or make them easy to access and modify

Oh dear... Having had the joy of wrestling with a 1000LoC functions (which liberally accessed various global variables) I can sympathize.

First of all, I'd strongly reccommend you to get and read the book "Working Effectively with Legacy Code" by Michael C. Feathers. It will give a lot of good ideas how to work, well, with the code you have.

Secondly: Consider your testing procedures. I assume that the new program is expected to work like the old pascal one, so make sure you have a solid set of tests to verify that.

Finally: There are several ways to get such a global variable blob under control. The best option (in the medium and long term) would probably be to untangle that ball of yarn, pack global variables that belong together into structs or classes, and use dependency injection to get them to the objects (and functions) that need them (i.e. the constructor of such classes demands a pointer to said struct).

//FlagsStruct.h
struct FlagsStruct
{
int Flag_1;
int Flag_2;
}

//WorksWithFlags.h
class WorksWithFlags
{
public:
WorksWithFlags(FlagsStruct* flags);
//...
}

That way you need to create the FlagsStruct once (and only once), then hand it to all those that need to work with it.

And regarding the const values - that is pretty much the only way to handle consts. You could too partition those up into groups that belong together and create individiual header files (with them as static consts in them) for those, but beyond that I don't see much that you could do about them. On the postive side: consts are (being read-only) rather benign "globals".

How would I avoid using a global variable here?

You need to assign the result back to the variables.

async def playerHand():
pH = []
phNum = 0
pH, pHnum = addCardP(phnum, pH)
pH, pHnum = addCardP(phnum, pH)
await ctx.send(pH)
await ctx.send(pHnum)


Related Topics



Leave a reply



Submit