Global Variable in a Package - Which Approach Is More Recommended

Global variable in a package - which approach is more recommended?

Some packages use hidden variables (variables that begin with a .), like .Random.seed and .Last.value do in base R. In your package you could do

e <- new.env()
assign(".sessionId", "xyz123", envir = e)
ls(e)
# character(0)
ls(e, all = TRUE)
# [1] ".sessionId"

But in your package you don't need to assign e. You can use a .onLoad() hook to assign the variable upon loading the package.

.onLoad <- function(libname, pkgname) {
assign(".sessionId", "xyz123", envir = parent.env(environment()))
}

See this question and its answers for some good explanation on package variables.

Global variables in packages in R

In general global variables are evil. The underlying principle why they are evil is that you want to minimize the interconnections in your package. These interconnections often cause functions to have side-effects, i.e. it depends not only on the input arguments what the outcome is, but also on the value of some global variable. Especially when the number of functions grows, this can be hard to get right and hell to debug.

For global variables in R see this SO post.

Edit in response to your comment:
An alternative could be to just pass around the needed information to the functions that need it. You could create a new object which contains this info:

token_information = list(token1 = "087091287129387",
token2 = "UA2329723")

and require all functions that need this information to have it as an argument:

do_stuff = function(arg1, arg2, token)
do_stuff(arg1, arg2, token = token_information)

In this way it is clear from the code that token information is needed in the function, and you can debug the function on its own. Furthermore, the function has no side effects, as its behavior is fully determined by its input arguments. A typical user script would look something like:

token_info = create_token(token1, token2)
do_stuff(arg1, arg2, token_info)

I hope this makes things more clear.

When to use global variables

One usual way is to use Method Value

Consider a struct type T with two methods, Mv, whose receiver is of type T, and Mp, whose receiver is of type *T.

type T struct { 
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver

var t T

The expression

T.Mv

yields a function equivalent to Mv but with an explicit receiver as its first argument; it has signature

func(tv T, a int) int

You can see an example of Method Value in this thread

// TODO: Get rid of the global variable.
var foo service

func handleFoo(w http.ResponseWriter, req *http.Request) {
// code that uses foo
}

func main() {
foo = initFoo()

http.HandleFunc("/foo", handleFoo)
}

One way to get rid of that global variable is to use method values:

type fooHandler struct {
foo service
}

func (h fooHandler) handle(w http.ResponseWriter, req *http.Request) {
// code that uses h.foo
}

func main() {
foo := initFoo()

http.HandleFunc("/foo", fooHandler{foo}.handle)
}

A new official approach for your global values is introduced in Go 1.7 with context.Context#Values.

Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions.

See "How to correctly use context.Context in Go 1.7"


Finally, in addition of being hard to test, global values can prevent vendoring.

See "To vendor or not to vendor, that is a question"

Many Go’s libaries have exported package variables. Those variables can be viewed as certain global states of a certain package.

Prior vendoring era, we can go get each imported package once and the global state of each imported package can be shared within all other imported packages.

Some devs may take it as granted and simply manipulate those global states at will.

However, with vendoring each imported package may have its own view of global states. Now a dev may found it impossible to change other package’s view of global state

Java - best practice for creating package-wide or global variables

If you're talking about constants, then they should be declared as static final fields in a class (never in an interface, according to Joshua Bloch).

If you're talking about settings which can change on the fly, then these could be either static fields in a class, or you could create a ConfigHandler class to manage the setting and fetching of configurable values.

Using class fields for mutable values might lead to concurrency problems, so if your application is multi-threaded it might be better to create a ConfigHandler class which manages concurrent access carefully and provides synchronized methods to avoid problems.

When is it ok to use a global variable in C?

Variables should always have a smaller scope possible. The argument behind that is that every time you increase the scope, you have more code that potentially modifies the variable, thus more complexity is induced in the solution.

It is thus clear that avoiding using global variables is preferred if the design and implementation naturally allow that. Due to this, I prefer not to use global variables unless they are really needed.

I can not agree with the 'never' statement either. Like any other concept, global variables are something that should be used only when needed. I would rather use global variables than using some artificial constructs (like passing pointers around), which would only mask the real intent.

Some good examples where global variables are used are singleton pattern implementations or register access in embedded systems.

On how to actually detect excessive usages of global variables: inspection, inspection, inspection. Whenever I see a global variable I have to ask myself: Is that REALLY needed at a global scope?

Global variables in Java

To define Global Variable you can make use of static Keyword

public class Example {
public static int a;
public static int b;
}

now you can access a and b from anywhere
by calling

Example.a;

Example.b;

Using global variables in a function

You can use a global variable within other functions by declaring it as global within each function that assigns a value to it:

globvar = 0

def set_globvar_to_one():
global globvar # Needed to modify global copy of globvar
globvar = 1

def print_globvar():
print(globvar) # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar() # Prints 1

Since it's unclear whether globvar = 1 is creating a local variable or changing a global variable, Python defaults to creating a local variable, and makes you explicitly choose the other behavior with the global keyword.

See other answers if you want to share a global variable across modules.



Related Topics



Leave a reply



Submit