Usage of Local Variables

Fields vs Local variables? When to use one or the other?

  1. Declare a variable as a field when it represents the *state* of the instance.
  2. A large function that's been split up isn't enough reason to promote local variables into fields. The impact on readability and maintainability is too significant:
    1. programmers will always have to reason whether the fields are part of the state or are they just some temporary calculation helpers;
    2. much, much harder to maintain thread-safety since the same fields are used for any concurrent method invocations.
    3. passing the variables from one inner method to another helps:
      1. independently understanding the exact functionality of the method;
      2. re-use the inner methods;
      3. unit-test the inner methods.
  3. Yes, pass around the local variables.
  4. In case there are just too much such variables, it's typical to group them in a convenient helper class, that functions as a struct. It increases readability and eases the usage.

When to use local variable instead of method?

First of all you should consider

  • Readability (which way is easier to understand and maintain).
  • Value consistency. If you get accustomed to cache the value in a variable, and at some case the value changes, then you might have a bug that is hard to spot.

Then comes the performance issues. For such trivial cases it might be equal or less efficient. Even if you used the variable 1000 times.

The compiler might translate if (someMethod()) -> if (true) if you are just returning a constant or reference (see Method inlining).


UPDATE

Just for recreational purposes (fooling around with homebrew pocket benchmark) (nothing serious like JMH).

  • Indicates that for simple cases there is no benefit of creating a variable to cache the result of method returning constants.
  • Weird thing I checked the generated bytecode (jdk 1.8.0_31) and Inlining$2#execute has 3 calls to calledStaticMethod (therefore no inlining on compilation). I must be missing something (Eclipse had its own compiler? options? misconceptions?) and the virtual machine JIT optimizer doing a terrific job.

source code (Inlining.java). Contains the almost harmless Benchmark class appended

// https://stackoverflow.com/questions/32500628/when-to-use-local-variable-instead-of-method
public class Inlining {
public static int calledStaticMethod() {
return 0;
}

public static void dumpValue(Object o) { // Fool compiler/JVM that value is going somewhere

}

public static void main(String[] args) {
float iterations = Benchmark.iterationsFor10sec(new Benchmark("cacheCall") {
@Override
public void execute(long iterations) {
int i1,i2,i3 = 0;
for (int i = 0; i < iterations; i++) {
int localVar = calledStaticMethod();
i1 = localVar;
i2 = i1 + localVar;
i3 = i2 + localVar;
}
dumpValue((Integer)i3);
}
});
System.out.printf("cacheCall: %10.0f\n", iterations);

iterations = Benchmark.iterationsFor10sec(new Benchmark("staticCall") {
@Override
public void execute(long iterations) {
int i1,i2,i3 = 0;
for (int i = 0; i < iterations; i++) {
i1 = calledStaticMethod();
i2 = i1 + calledStaticMethod();
i3 = i2 + calledStaticMethod();
}
dumpValue((Integer)i3);
}
});
System.out.printf("staticCall: %10.0f\n", iterations);

// borderline for inlining, as instance methods might be overridden.
iterations = Benchmark.iterationsFor10sec(new Benchmark("instanceCall") {
public int calledInstanceMethod() { return calledStaticMethod(); }
@Override
public void execute(long iterations) {
int i1,i2,i3 = 0;
for (int i = 0; i < iterations; i++) {
i1 = calledInstanceMethod();
i2 = i1 + calledInstanceMethod();
i3 = i2 + calledInstanceMethod();
}
dumpValue((Integer)i3);
}
});
System.out.printf("instanceCall: %10.0f\n", iterations);
}

}

abstract class Benchmark {
private String name;
public Benchmark(String s) { name = s; }
public String getName() { return name; }
public abstract void execute(long iterations);
public static float iterationsFor10sec(Benchmark bm) {
long t0 = System.nanoTime();
long ellapsed = 0L;
// Calibration. Run .5-1.0 seconds. Estimate iterations for .1 sec
final long runtimeCalibrate = (long)0.5e9; // half second
long iterations = 1L;
while (ellapsed < runtimeCalibrate) {
bm.execute(iterations);
iterations *= 2;
ellapsed = System.nanoTime() - t0;
}
iterations--; // Actually we executed 2^N - 1.
int innerIterations = (int) ((double)iterations * 1e8 /* nanos/inner */ / ellapsed);
if (innerIterations < 1) { innerIterations = 1; }
// run rest of the time
final long runtimeTotal = (long)1e10;
// outer loop
while (ellapsed < runtimeTotal) {
// delegate benchmark contains inner loop
bm.execute(innerIterations);
iterations += innerIterations;
ellapsed = System.nanoTime() - t0;
}
// execution time might exceed 10 seconds. rectify number of iterations
return (float)iterations * 1e10f /* nanos total */ / (float)ellapsed;

}
}

output:

cacheCall: 21414115328
staticCall: 21423159296
instanceCall: 21357850624

Is it possible to take the Local Variable of a Function and convert it to a Global Variable or use it in an other Function

There are a few ways in Python through which you can manipulate global and local variables of different objects from other objects. Most of those are advanced coding and some include fiddleing with Python interpreter mechanisms. However, what you want is quite simple:

some_global_var = None # Declare the global variable outside of both functions in advance

def f1 (a):
global some_global_var
some_global_var = a*10

def f2 (a):
return some_global_var*a

Note that global variables are accessible for read from a function, but unless you declare it as global at the top of your function, assigning a value to it will just make a local variable with the same name, and the global one will be left alone.

There are good reasons for that, some of which are already pointed out in the other answer.

To do the same thing, but much more acceptable would be to use objects:

class Math:
some_attribute = None
def f1 (self, a):
self.some_attribute = a*10

def f2 (self, a):
return self.some_attribute*a
m = Math()
m.f1(10)
print(m.f2(20))

Perhaps you may want to learn objective oriented programming for your project. It is usually the solution when functions need to share resources in a way you asked for.

Some programmers are positively afraid of global variables and are trying to avoid them at all costs. That's because they are very bad at debugging and, in short, are bad programmers.

Using them is a bit tricky because you must always keep track of your global variables and what is happening to them, and where, in order not to make any mistakes. This can be especially nasty for big projects in low-level programming languages like C. But sometimes they are simply unavoidable and you would make a bigger mess by avoiding them. To help you remember what you are dealing with Python has the keyword global.

Your case though is not exactly one where you would use a global variable. But you must decide. When you use them, make sure that they are used for exactly one purpose and avoid using the same name for local variables anywhere else and you will be fine. Also, minimize the number of functions that are allowed to actually change them.

Usage of local variables

Use local. Using your example:

local({ 
V1 = c(1,2,3);
V2 = c(1,2,3);
P = inner_product(V1, V2);
print(P);
})
# the variable V1, V2, P are undefined here!

How to use a local variable in a frequently used function without declaring it every time?

Yes thats a local variable i.e cannot access it outside this scope.

This is fine to do and in fact one of the recommended practices.

Yes, memory is used each time its called but then it is cleared/garbage collected when the function is done executing(assuming no other leaks).

One more thing though, you could change the var to a let for even better block scoping... although not necessary in this very simple case.

Usage of global variables and local variables in different subs

Local Variable

First of all declare every variable as local as possible. Eg if it is needed in only one procedure/function declare it there.

Local Variable (Passed as Parameter)

If you need to access a variabe in more than one procedure/function then it is a good idea to pass it to the next function as a parameter. This can be done ByRef (which is default) or ByVal.

Sub ProcedureA()
Dim ParamA As String
ParamA = "AAA"
Dim ParamB As String
ParamB = "BBB"

ProcedureB ParamA, ParamB

Debug.Print ParamA 'returns 111
Debug.Print ParamB 'returns BBB
End Sub

Sub ProcedureB(ByRef Param1 As String, ByVal Param2 As String)
Param1 = "111" 'this will change ParamA in ProcedureA too
Param2 = "222" 'this value will only be changed in ProcedureB
End Sub

While using ByRef (by reference) makes it possible to change the parameter in ProcedureB and have it also changed in ProcedureA, but the parameter that is passed ByVal (by value) does not change in ProcedureA.

Here it technically doesn't make any difference if you name the variables differently or use the same name. Use the name that is most meaningful in each of the procedures would be a good practice (see headline variable names below).

Actually I think it is also a good practice to always specify if it is ByRef or ByVal and not use the default. When using the default you always have to remember that it is ByRef by default in VBA but in VB.NET the default is ByVal which can easily get confusing (at least me).

After ProcedureA ends the variables are not available anymore (data is lost).

Global Variable

If you want the data to be persistant and accessible in more than one function then use global variabes (use them as rarely as possible).

Dim GlobalVarA As String

Sub ProcedureA()
GlobalVarA = "AAA"
End Sub

Sub ProcedureB()
Debug.Print GlobalVarA 'return AAA (if ProcedureA was run before)
End Sub

Note that in this case any procedure can change the value of GlobalVarA. If you pass it as a parameter as explained above, then only the procedures that the variable is passed to can access the variable.

Global variables will lose their data when Excel VBA ends (or file gets closed).

A down side of using global variables in a procedure is, you need always to check its value before using it the first time. Because if it was not initialized yet it is Empty or Nothing. For example (above) when running ProcedureB you cannot rely on that ProcedureA was already run before. So you would need to check the value of GlobalVarA before using it in ProcedureB especially if it is an object you have to test if for not beeing Nothing or you will easily run into errors.

Local vs. Global

So we can summarize, that restricting the access to a variable as much as possible makes your code more secure and more reliable (no other function can accidentally change it if it is only declared locally). Only use global variables if you really need to.

Re-Use Variable names

To re-use variable names is no problem in general if they are declared locally. But it gets tricky if you use the same name for a global and local variable (then VBA prefers the local one!)

Dim VarA As String 'global

Sub ProcedureA()
Dim VarA As String 'same name local
VarA = "AAA" 'this uses always the local variable!
End Sub

Sub ProcedureB()
Debug.Print VarA 'this uses the global variable and it is empty (after ProcedureA is run)
End Sub

In general it is a very good practice to use meaningful variable names only. That means instead of calling a variable rng1 and rng2 call them for example InputRange and OutputRange. Also if you need a counter (to eg loop through rows and columns) often i and j are used, but it is much more readable if you use eg iRow and iCol as variable names.

Option Explicit

In order to force a proper variable declaration I recommend always to activate Option Explicit: In the VBA editor go to ToolsOptionsRequire Variable Declaration. This prevents you from mis-typing variable names and accidentally introduce new variables.



Related Topics



Leave a reply



Submit