I found a quirky bug in my code some time back, and realised that the cause of the bug was quite a useful Apex feature viz. SObjects and Apex classes are passed by reference and not value.
What does this mean you say? Let’s start by defining what passing by value means.
In a nutshell, if you pass a variable to a method and it’s a Force.com primitive type(Integer, String etc.) it will be passed by value meaning that the value of the variable and not the variable itself is passed to the method e.g.
String val = ‘Hello’;
public void byValue(String v){
System.debug(‘Value in: ‘+v);
v = ‘Goodbye’;
System.debug(‘Value out: ‘+v);
}
byValue(val);
System.debug(‘Value of val: ‘+val);
Executing this piece of code(perhaps as an anonymous block) would give the following,
Value in: Hello
Value out: Goodbye
Value of val: Hello
As can be seen here, when a variable is passed by value, any changes to the variable within the method are lost after the method execution completes.
The contrary is true when working with SObjects and Apex classes e.g.
public class Value{
public String name{get;set;}
public Value(String n){
name= n;
}
}
Value val = new Value(‘Hello’);
public void byReference(Value v){
System.debug(‘Value in: ‘+v.name);
v.name = ‘Goodbye’;
System.debug(‘Value out: ‘+v.name);
}
byReference(val);
System.debug(‘New value is: ‘+val.name);
This code yields,
Value in: Hello
Value out: Goodbye
New value is: Goodbye
Meaning that any changes that are made to the class(or SObject) within the method are retained even after the method finishes executing. This is passing by reference my friend and it’s used because it’s more efficient to pass pointers-to-memory-locations around than it is to pass entire objects(or lists of objects) around.
Not knowing this can be quite frustrating and I’m not sure how developers without a background in Java or C++ might realise their code is working according to these rules(Yeah I know they can RTM but how would they know what to look for huh?). That said this functionality, if used correctly, can make your code quite neat.
This might serve as a useful example:
You have a list of SObjects that you need to wrap in order to add some extra functionality to a page. You might decide to implement this so,
1. Fetch a list of records from database.
2. Create a list of wrappers using the records.
3. Display wrappers on page.
4. User edits records and clicks a ‘Save’ button.
5. Your save method fetches the records out of the wrappers and puts them into another list. It then saves this list of records.
Lo-and-behold! Armed with our new knowledge of passing by reference we now know that Step 5 is unnecessarily verbose. We replace it with,
5. Save the list you fetched in Step 1.
And we’re done! The SObjects in the first list are precisely the same as the SObjects within the list of wrappers. Well sort of. This is a bit of an educated guess but I think neither list actually ‘has’ any SObjects, instead they contain pointers to memory locations. This would be quite a bit quicker than passing the entire objects around your application and it pretty fantastic.
If you have any other situations where passing by reference might be valuable I’d be keen to hear about them.
Thanks, I’m one of these: “…developers without a background in Java or C++ might realise their code is working according to these rules” and your explanation is simple yet incredibly clear. Thanks again.
Thanks, I’m one of these: “…developers without a background in Java or C++ might realise their code is working according to these rules” and your explanation is simple yet incredibly clear. Thanks again.
Just as a note to this I was trying to retain the values for primitive type(Integer, String etc.) when I passed them into a sub function. As you said the values when not returning to the original function. To get round this I had to declare the primitive type variables a private global variables so that the values are retained after processing has happened in the sub function.
PS love the articles.
Thanks bud.
Just as a note to this I was trying to retain the values for primitive type(Integer, String etc.) when I passed them into a sub function. As you said the values when not returning to the original function. To get round this I had to declare the primitive type variables a private global variables so that the values are retained after processing has happened in the sub function.
PS love the articles.
Thanks bud.