Variable Scope in Apex

In Salesforce by Alex0 Comments

At some point all of us have seen “Compile Error: Variable does not exist” when saving an Apex class. One of the most common causes of this (after forgetting to create the variable in the first place) is an issue with the scope of the variable.

Variable scope is a concept that I’ve found new programmers (or programmers coming from environments with different scoping rules) often struggle with. I’ve put together some examples that clarify how variable scope works in Apex.

In computer programming, the scope of a name binding – an association of a name to an entity, such as a variable – is the part of a computer program where the binding is valid: where the name can be used to refer to the entity. In other parts of the program the name may refer to a different entity (it may have a different binding), or to nothing at all (it may be unbound).

To put that in slightly simpler terms, scope determines which other parts (e.g. variables) of your code that your code can ‘see’.

Apex has fairly simple scoping rules:

  • Curly braces are used to indicate child scopes (similar to other C-like languages).
  • You can access variables that have been declared in your current scope and parent scope(s), but not those defined in child scopes or parallel scopes.
  • You cannot access instance variables from a static scope without an object reference.
  • Uses lexical scoping.

Rather than try and explain scope in words I’ll move straight into the examples as they are the clearest explanation I can give.

Instance And Local Variables

In object-oriented programming with classes, an instance variable is a variable defined in a class (i.e. a member variable), for which each instantiated object of the class has a separate copy, or instance.

Basically, instance variables are your class level variables.

In computer science, a local variable is a variable that is given local scope. Local variable references in the function or block in which it is declared override the same variable name in the larger scope.

Local variables are those that have been defined at a lower level than the class level, for example within a method or within an ‘if’ block.

These examples concentrate on the interactions between child and parent scopes, the examples in the next section deal with parallel scopes.

public class Examples { // Begin class scope
    Integer classVariable;

    void instanceMethod() { // Begin method scope
        Integer methodVariable;

        // We can access classVariable because it is defined in a parent scope
        classVariable = 0; // OK!

        // We can access methodVariable because it's defined in the current scope
        methodVariable = 0; // OK!

        if(true) { // Begin inner 'if' scope
            Integer methodInnerVariable;

            // We can access classVariable because it is defined in a parent scope
            classVariable = 0; // OK!

            // We can access methodVariable because it's defined in a parent scope
            methodVariable = 0; // OK!

            // We can access methodInnerVariable because it's defined in the current scope
            methodInnerVariable = 0; // OK!
        } // End inner 'if' scope

        // We cannot access methodInnerVariable here because it is in a child scope
        methodInnerVariable = 0; // ERROR!
    } // End method scope
} // End class scope

Parallel Scopes

You cannot access variables that have been declared in parallel (i.e. the same level) scopes in Apex. If you need to access a variable across two parallel scopes then the variable needs to be declared in a parent scope that is accessible to both, e.g. classVariable and methodVariable in the below examples.

public class ParallelExamples { // Begin class scope
    Integer classVariable;
    
    void instanceMethod1() { // Begin method1 scope
        Integer method1Variable;
        
        // We can access classVariable because it's defined in a parent scope
        classVariable = 0; // OK!

        // We can access method1Variable because it's defined in the current scope
        method1Variable = 0; // OK!
    } // End method1 scope

    void instanceMethod2() { // Begin method2 scope
        // We can access classVariable because it's defined in a parent scope
        classVariable = 0; // OK!

        // We cannot access method1Variable because it's defined in a parallel scope
        method1Variable = 0; // ERROR!
    } // End method2 scope

    void instanceMethod3() { // Begin method3 scope
        Integer methodVariable;
        
        if(true) { // Begin inner 'if' scope 1
            Integer innerScope1Variable;
            
            // We can access classVariable because it's defined in a parent scope
            classVariable = 0; // OK!
            
            // We can access methodVariable because it's defined in a parent scope
            methodVariable = 0; // OK!

            // We can access innerScope1Variable because it's defined in the current scope
            innerScope1Variable = 0; // OK!
        } // End inner 'if' scope 1

        if(true) { // Begin inner 'if' scope 2
            // We can access classVariable because it's defined in a parent scope
            classVariable = 0; // OK!
            
            // We can access methodVariable because it's defined in a parent scope
            methodVariable = 0; // OK!
            
            // We cannot access innerScope1Variable because it's defined in a parallel scope
            innerScope1Variable = 0; // ERROR!
        } // End inner 'if' scope 2
    } // End method3 scope
} // End class scope

Static (aka. Class) Variables

In object-oriented programming with classes, a class variable is a variable defined in a class of which a single copy exists, regardless of how many instances of the class exist.

If you need more details about static methods and the difference between them and instance methods then I recommend reading the Static and Instance Methods, Variables, and Initialization Code section of the Apex Code Developer’s Guide.

Static variables and scopes follow exactly the same rules as instance variables and scopes when they are interacting with other static variables and scopes.

public class StaticExamples { // Begin class scope
    static Integer staticClassVariable;

    static void staticMethod1()
    { // Begin method1 scope
        Integer staticMethodVariable;

        // We can access classVariable because it is defined in a parent scope
        staticClassVariable = 0; // OK!

        // We can access methodVariable because it's defined in the current scope
        staticMethodVariable = 0; // OK!

        if(true) { // Begin inner 'if' scope
            Integer staticMethodInnerVariable;

            // We can access classVariable because it is defined in a parent scope
            staticClassVariable = 0; // OK!

            // We can access methodVariable because it's defined in a parent scope
            staticMethodVariable = 0; // OK!

            // We can access methodInnerVariable because it's defined in the current scope
            staticMethodInnerVariable = 0; // OK!
        } // End inner 'if' scope

        // We cannot access methodInnerVariable here because it is in a child scope
        staticMethodInnerVariable = 0; // ERROR! 
    } // End method1 scope
    
    static void staticMethod2() { // Begin method2 scope
        // We can access classVariable because it is defined in a parent scope
        staticClassVariable = 0; // OK!

        // We can access methodVariable because it's defined in the current scope
        staticMethodVariable = 0; // OK!
        
        // We cannot access staticMethodVariable because it's defined in a parallel scope
        staticMethodVariable = 0; // ERROR!
    } // End method2 scope
} // End class scope

Mixing Instance and Static Variables

Here is where things get a little bit more complicated.

From an instance scope you can access static variables in your current scope and parent scope(s), however from a static scope you cannot access instance variables without an object reference.

public class MixedExamples {
    Integer classVariable;
    static Integer staticClassVariable;

    void instanceMethod() { // Begin instance method scope
        // We can access instanceClassVariable because it's defined in a parent scope
        classVariable = 0; // OK!

        // We can access staticClassVariable because it's defined in a parent scope
        staticClassVariable = 0; // OK!
    } // End instance method scope

    static void staticMethod(MixedExamples examples) { // Begin static method scope
        // We cannot access instanceClassVariable because it's an instance variable and we are in a static scope
        classVariable = 0; // ERROR!

        // We can however access it if we have an object reference (passed into the function)
        examples.classVariable = 0; // OK!

        // We can access staticClassVariable because it's defined in a parent scope
        staticClassVariable = 0; // OK!
    } // End static method scope
}

These examples are not intended to be comprehensive, but they should cover most common situations.

Variable scope is one of the fundamental concepts in computer science so having a better understanding of how it works is never a bad thing.