Fields vs Local variables? When to use one or the other?
- Declare a variable as a field when it represents the *state* of the instance.
- 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:
- programmers will always have to reason whether the fields are part of the state or are they just some temporary calculation helpers;
- much, much harder to maintain thread-safety since the same fields are used for any concurrent method invocations.
- passing the variables from one inner method to another helps:
- independently understanding the exact functionality of the method;
- re-use the inner methods;
- unit-test the inner methods.
- Yes, pass around the local variables.
- 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 tocalledStaticMethod
(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 Tools › Options › Require Variable Declaration. This prevents you from mis-typing variable names and accidentally introduce new variables.
Related Topics
Stargazer Left Align Latex Table Columns
R: Interactive Plots (Tooltips): Rcharts Dimple Plot: Formatting Axis
From [Package] Import [Function] in R
Error in Bind_Rows_(X, .Id):Column Can't Be Converted from Factor to Numeric
Generate 3 Random Number That Sum to 1 in R
Adding Multiple Shadows/Rectangles to Ggplot2 Graph
How to Use a Character as Attribute of a Function
Dplyr . and _No Visible Binding for Global Variable '.'_ Note in Package Check
Frustration Using Rjava to Call a Third Party Java Jar
How to Print the Name of Current Row When Using Apply in R
Converting Date Column in Data Frame
Nls Troubles: Missing Value or an Infinity Produced When Evaluating the Model
How to Bookmark and Restore Dynamically Added Modules
Create Fillable PDF Textbox via R
Ggplot2: How to Set the Default Fill-Colour of Geom_Bar() in a Theme