What Makes A Data Type “Primitive”?
Welcome back! Last episode we covered variables. Today we’re going one level deeper into the types those variables can be, starting with the primitives.
There are three things that make a data type primitive, and they’re worth committing to memory because all three will bite you at some point:
1. They’re built into the language. You can use them immediately, in a totally empty org, without declaring anything anywhere.
2. They’re passed by value, not by reference. This is the big one, and we’ll spend most of this post on it.
3. You can’t modify their behaviour. You can’t add methods to Integer. You can’t bolt a field onto String. Whatever Salesforce gave you is what you get. That’s not true in every language, but it’s true here.
The Full List
Straight from the Apex Developer Guide, here’s what you get:
Blob //binary data, e.g. an attachment's body
Boolean //true, false, or null
Date //a date with no time component
Datetime //a date AND a time
Decimal //a number with decimal points, arbitrary precision
Double //a 64-bit number with decimal points
ID //an 18 character Salesforce record Id
Integer //a 32-bit whole number
Long //a 64-bit whole number
Object //the generic type everything can be cast to
String //a set of characters in single quotes
Time //a time with no date componentA few practical notes on these:
Use Decimal for money, not Double. Doubles are floating point and will eventually produce results like 0.30000000000000004. Currency fields in Salesforce come back as Decimal for exactly this reason.ID is its own type, and it’s worth using instead of String when you’re holding a record Id. Apex will actually validate that the value looks like a real Id.Object is a bit of an odd one out. It’s listed as a primitive, but it’s the generic supertype that everything in Apex can be cast to. It’s genuinely useful when you need to write something that handles any type, and genuinely dangerous when you use it to avoid thinking about types.
Passed By Value: The Important Bit
This is the single most important thing in this episode, so let’s do it properly.
When you pass a primitive into a method, Apex hands that method a copy of the value. The method can do whatever it likes to that copy and your original variable is completely untouched.
Look:
public class PrimitiveExample
{
public void runIt()
{
Integer myNumber = 1;
changeTheNumber(myNumber);
//This still prints 1. Not 500.
System.debug('myNumber is now ::: ' + myNumber);
}
private void changeTheNumber(Integer numberToChange)
{
numberToChange = 500;
}
}Run that and the debug line says myNumber is now ::: 1.
Why? Because changeTheNumber never received myNumber. It received a copy of the number 1. It set that copy to 500, then the method ended and the copy evaporated. Your original variable never knew anything happened.
Now, why does this matter? Because non-primitives behave completely differently, and if you don’t know which is which you will eventually spend an afternoon staring at code wondering why a list you passed into a helper method came back modified. We’ll cover that in the next episode, and it’s the single most common source of “wait, what?” bugs for newer Apex developers.
You Can’t Change What They Do
The third rule is the least dramatic but still worth knowing. Primitive types are closed. You cannot extend String to add your own toTitleCase() method. You cannot subclass Integer.
What you do instead is write a utility class:
public class StringUtils
{
public static String toTitleCase(String input)
{
if (String.isBlank(input))
{
return input;
}
return input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase();
}
}Slightly less elegant than extending the type directly, but it’s the Apex way and you’ll see this pattern everywhere.
Worth knowing: the primitives already come with a lot of built-in methods. Before you write a utility, check the String methods documentation and its equivalents. There’s a very good chance it already exists.
What’s Next
Three rules, that’s all you need to carry forward: primitives are built in, passed by value, and closed to modification.
In the next episode we cover non-primitive types, which break all three of those rules, and I’ll show you exactly what passing by reference looks like when it surprises you.
See you next time!
Get Coding With The Force Merch!!
We now have a redbubble store setup so you can buy cool Coding With The Force merchandise! Please check it out! Every purchase goes to supporting the blog and YouTube channel.
Get Shirts Here!
Get Cups, Artwork, Coffee Cups, Bags, Masks and more here!
Check Out More Coding With The Force Stuff!
If you liked this post make sure to follow us on all our social media outlets to stay as up to date as possible with everything!
Youtube
Patreon
Github
Facebook
Twitter
Instagram
Salesforce Development Books I Recommend
Advanced Apex Programming
Salesforce Lightning Platform Enterprise Architecture
Mastering Salesforce DevOps
Good Non-SF Specific Development Books:
Clean Code
Clean Architecture