3

I was able to update the value of a local variable in a method from a different class. I am trying to understand how is it possible! Isn't that variable out of scope for another method. Moreover the method which adds a string does not even return back the variable. I don't see it like a object reference been updated. I see something strange but I might not be clear on this concept.

TestSampleVariableAssgment

public class TestSampleVariableAssgment{

public static void callVarAssignment(){
    List<String> sa = new List<String>();
    system.debug('Before ======>' + sa);
    CheckVariableChange.abc(sa);
    system.debug('After ======>' + sa);
}

}

CheckVariableChange

public class CheckVariableChange{

    public static void abc(List<String> sampleString){
        sampleString.add('Hello');
    }

}

Execute Anonymous:

TestSampleVariableAssgment.callVarAssignment();

enter image description here

5

Variables can be passed between methods, even in different classes (so long as the method itself is at least public). Furthermore, except for "primitives" (such as String, Decimal, etc), other types of objects, including "collections" (Set, List, and Map), SObjects, and other complex data types, are almost always passed by "reference." This means that when one method has a reference to a variable in another method, the method that provided the reference will have its value updated.

In other words:

I don't see it like a object reference been updated.

Is factually incorrect. Only primitive values are passed by value, while non-primitives are passed by reference.

It's easier to see this behavior if you use methods in the same class:

public void doA() {
  String[] values = new String[0];
  System.debug('Before...' + String.join(values, ' '));
  doB(values);
  System.debug('After...' + String.join(values, ' '));
}
public void doB(String[] valuesToUpdate) {
  valuesToUpdate.add('Hello');
  valuesToUpdate.add('World');
}

The output, of course, would be:

Before...

After...Hello World

It doesn't matter if the methods are in the same class, in different classes in the same namespace, or in different namespaces entirely. As long as you have a reference to the variable, you can update the variable and have those changes appear in the calling method.

As another example, using a custom class:

public class Wrapper {
  public Integer value;
  public void doubleValue() {
    value *= 2;
  }
}
public void methodA() {
  Wrapper w = new Wrapper();
  w.value = 5;
  doubleWrapper(w);
  System.assertEquals(10, w.value);
  callDouble(w);
  System.assertEquals(20, w.value);
}
public void doubleWrapper(Wrapper item) {
  item.value *= 2;
}
public void callDouble(Wrapper item) {
  item.doubleValue();
}

Again, because we're passing a non-primitive value, it is passed by reference, so the calling method gets to see the new values.

This behavior means that you can create complex methods that can essentially return complex data using a pattern we would call an "out parameter" (meaning, the output is returned in the parameter). Some languages, like C#, provide an explicit mechanism for this, while languages like Java and Apex are more implicit.

You'll also want to read Primitive Data Types. Only the types in the list are passed by value, except for Object, which is passed as either a value or a reference, depending on the value that's inside of the Object.

Also, see this question where I go in to more details about how references work.


Note: From a technical perspective, everything is passed by value. However, non-primitive objects are always stored as a memory reference to the heap, so you end up passing a value that is a reference.

For example, when you write:

Account a = new Account();
a.Name = 'Test';

new Account() creates an object on the heap, and stores the reference to the object in a. Later, when you access a.Name, you're "dereferencing" a to find the Name member of the Account that was created on the heap.

If you understand how that works, then you'll understand what I'm trying to convey; passing an Account as a parameter doesn't literally copy the entire heap value, which would be an expensive operation, but simply passes the reference, which is just the value stored in a.

You can observe a related behavior if you just use variables. Consider the following:

Account a = new Account(), b = a;
a.Name = 'Test';
System.assertEquals(b.Name, 'Test');

This, of course, passes, because b is simply a reference to a. Unless you clone() an sObject, any reference to it will affect the original reference as well.

| improve this answer | |
  • Great! Thanks for the effort in explaining in so much details. – Arnold Dec 13 '17 at 4:28
0

Static variables are persistent across the context of whole apex transaction. I suggest reading this doc

A static variable is static only within the scope of the Apex transaction. It’s not static across the server or the entire organization. The value of a static variable persists within the context of a single transaction and is reset across transaction boundaries. For example, if an Apex DML request causes a trigger to fire multiple times, the static variables persist across these trigger invocations.

To store information that is shared across instances of a class, use a static variable. All instances of the same class share a single copy of the static variable. For example, all triggers that a single transaction spawns can communicate with each other by viewing and updating static variables in a related class. A recursive trigger can use the value of a class variable to determine when to exit the recursion.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.