Piotr Gajek
written by Piotr Gajek
posted on October 15, 2023
Technical Architect and Full-stack Salesforce Developer. He started his adventure with Salesforce in 2017. Clean code lover and thoughtful solutions enthusiast.
Table of Content

Type Casting in Apex

Hello devs,

What are Upcasting and Downcasting? How can you cast Apex Map, List, and Set? What is a supertype, and what is the difference between SObject and Object? Answers to these questions and much more can be found in this post!

Let's begin.

Before We Start

I am using different emojis to grab your attention:

  • 🚨 - Unexpected casting behavior.
  • βœ… - Code that works.
  • ❌ - Code that does not work.

Supertype

What supertype is?

A supertype is an abstract/virtual class or an interface that is used by a child class.

e.g.

Interface

public interface Parent {
    void display();
}

public class Child implements Parent {
    public void display() {
        System.debug('Hello Parent Interface!');
    }
}

The Parent interface is a supertype for the Child class.

A class can implements many interfaces, meaning that a class can have many supertypes.

Abstract

public abstract Parent {
    abstract void display();
}

public class Child extends Parent {
    public override void display() {
        System.debug('Hello Parent Abstract Class!');
    }
}

The Parent abstract class is a supertype/superclass for the Child class.

A class can extends only one abstract class, but it can still implements many interfaces.

Virtual

public virtual Parent {
    virtual void display() {
        System.debug('Hello From Parent Virtual Class!');
    }
}

public class Child extends Parent {
    public override void display() {
        System.debug('Hello Parent Virtual Class!');
    }
}

The Parent virtual class is a supertype/superclass for the Child class.

A class can extends only one virtual class, but it can still implements many interfaces.

Upcasting vs Downcasting

You know what supertype is, it's necessary to understand the difference between Upcasting and Downcasting.

Upcasting and Downcasting in Apex

Reference

To better understand upcasting and downcasting, we need some examples.

We have two classes (it can be also class and interface), Parent and Child.

  • Parent is a virtual class and has a virtual method.
  • Child extends the Parent class and override the virtual method.

If you don't understand what virtual means, you can refer to the Abstract, Virtual, Interface in Apex post.

public virtual class Parent {
    public String parentProperty;

    public virtual void display() {
        System.debug('Method from Parent');
    }
}
public class Child extends Parent {
    public String childProperty;

    public override void display() {
        System.debug('Method from Child');
    }

    public void childMethod() {
        System.debug('Child secret method');
    }
}
Parent parent = new Parent();
parent.parentProperty = 'Parent Property Test';
parent.display();
// 'Method from Parent'
Child child = new Child();
child.childProperty = 'Parent Property Test';
child.childMethod();
// 'Child secret method'
child.display();
// 'Method from Child'

Upcasting

  • Child extends the Parent class. It means that Parent is a supertype/superclass for Child. Because of this, the following syntax: Parent parent = new Child(); is valid.
  • Casting a subclass (Child) to a supertype/superclass (Parent) is called Upcasting.
  • Upcasting can be either explicit or implicit.

Implicit Upcasting

Upcasting can be done implicitly.

βœ…

Parent parent = new Child();

Explicit Upcasting

Code should be as simple as possible (KISS rule), so the better approach is to use implicit upcasting.

βœ… ❌

Parent parent = (Parent) new Child();

Access

Parent parent = new Child();
parent.childProperty = 'Child Property Test';
// Variable does not exist: childProperty
parent.childMethod();
// Method does not exist or incorrect signature: void childMethod() from the type Parent

The parent variable has access to:

  1. Parent public variables.
  2. Parent public methods.
  3. Child ONLY overriden methods.

Downcasting

  • Casting a supertype/superclass (Parent) to a subclass (Child) is called Downcasting.
  • Upcasting can be done ONLY explicitly.

Implicit Downcasting

Downcasting CANNOT be implicit. Why?

  • There can be many children of the Parent class. e.g public class Child2 extends Parent { ... }.
  • Apex needs to know to what type the variable should be cast to.

❌

Parent parent = new Child();
Child child = parent;
// Illegal assignment from Parent to Child

Explicit Downcasting

You have to cast explicitly (Child) so the compiler checks in the background if this type of casting is possible or not. If not, you will get System.TypeException: Invalid conversion from runtime type Parent to Child.

❌

Parent parent = new Parent();
Child child = (Child) parent;
// System.TypeException: Invalid conversion from runtime type Parent to Child

βœ…

Parent parent = new Child();
Child child = (Child) parent;
child.parentProperty = 'Parent Property Test';
child.childProperty = 'Child Property Test';
child.display();
// 'Method from Child'

Access

The child variable has access to:

  1. Parent public variables.
  2. Parent public methods.
  3. Child ALL public methods and variables.

SObject

SObject Class

SObject is a supertype for:

  • all standard objects (Account, Contact, etc.)
  • all custom objects (MyCustomObject__c)

βœ…

SObject account = new Account(Name = 'My Account');
SObject myObject = new MyCustomObject__c();

Object

Object is a supertype for:

  • all standard objects
  • all custom objects
  • all apex classes
  • all collections (List, Set and Map)
  • all apex types (Integer, String, Boolean)

βœ…

Object account = new Account(Name = 'Test Account');
Object myObject = new MyCustomObject__c();
Object myClass = new MyClass();
Object myList = new List<String>();
Object myName = 'Beyond The Cloud';

Methods inherited from Object class

toString()

public class A {}

System.debug(new A().toString()); // A:[]

public class A {
   public override String toString() {
       return 'Hello toString()';
   }
}

System.debug(new A().toString()); // 'Hello toString()'

equals()

public class A {}

System.debug(new A().equal('Some String')); // false

hashCode()

public class A {}

System.debug(new A().hashCode()); // 2069582068
System.debug('Some String'.hashCode()); // 2147069117

clone()

public class A {}

System.debug(new A().clone());

SObject and Object

SObject and Object - instanceOf

Assert.isTrue(new Contact() instanceOf Object);
// Operation instanceOf is always true since an instance of Contact is always an instance of Object

Assert.isTrue(new Account() instanceOf Object);
// Operation instanceOf is always true since an instance of Account is always an instance of Object

SObject contact = new Contact();
Assert.isTrue(contact instanceOf Object);
// Operation instanceOf is always true since an instance of SObject is always an instance of Object
Expression is instanceOf
SObject instanceOf Object TRUE βœ…
  • SObject is an instance of Object. Object is a supertype for SObject.

SObject and Object - casting

Object to SObject

Downcasting

  • Object needs to be explicitly cast to SObject.

Why?

  • Object is a supertype of SObject.
  • Conversion from Object to SObject is called Downcasting.
  • As you already know from Downcasting section. Downcasting needs to be explicit (SObject).

❌

// Implicit downcasting
Object objectContact = new Contact();
SObject sObjectContact = objectContact;
// Illegal assignment from Object to SObject

βœ…

// Explicit downcasting
Object objectContact = new Contact();
SObject sObjectContact = (SObject) objectContact;

SObject to Object

Upcasting

  • SObject can be explicitly or implicitly cast to Object.

Why?

  • Object is a supertype of SObject.
  • Conversion from SObject to Object is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.

βœ…

// Explicit upcasting
SObject sobjectAccount = new Account();
Object objectAccount = sobjectAccount;

Inherited methods

  • Interestingly, Object is a supertype for SObject, but SObject does NOT inherit Object methods like toString(), equals(), hashCode(), clone().
    SObject has all of the following methods SObject class methods..

❌

SObject sObjectAccount = new Account();
System.debug(sObjectAccount.toString());
// Method does not exist or incorrect signature: void toString() from the type SObject

βœ…

Object objectAccount = new Account();
System.debug(objectAccount.toString());
// Account:{}

However, all Apex Classes inherit Object methods (toString(), equals(), hashCode(), clone()).

βœ…

Parent parent = new Parent();

System.debug(parent.toString());
// Parent:[parentProperty=null]

System.debug(parent.equals('SomeValue'));
// false

System.debug(parent.hashCode());
// 296136299

System.debug(parent.clone());
// Parent:[parentProperty=null]

Standard/Custom Object

Standard/Custom Object - instanceOf

Assert.isTrue(new Account() instanceOf SObject);
// Operation instanceOf is always true since an instance of Account is always an instance of SObject

Assert.isTrue(new Account() instanceOf Object);
// Operation instanceOf is always true since an instance of Account is always an instance of Object
Expression is instanceOf
Standard/Custom Object instanceOf SObject TRUE βœ…
Standard/Custom Object instanceOf SObject TRUE βœ…
Standard/Custom Object instanceOf Object TRUE βœ…
  • Standard/Custom Object is an instance of SObject and Object.
  • SObject and Object are supertypes for Standard/Custom Objects.

Standard/Custom Object to SObject - casting

Standard/Custom Object to SObject

Upcasting

Why it works?

  • SObject is a supertype for Account, Contact, and other standard or custom objects.
  • Conversion from Standard/Custom Object to SObject is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.

βœ…

// Implicit upcasting
Account account = new Account(Name = 'My Account');
SObject myAccount = account;

SObject to Standard/Custom Object

Downcasting

Why it works?

  • SObject is a supertype for Account, Contact, and other standard or custom objects.
  • Conversion SObject to Standard/Custom Object is called Downcasting.
  • As you already know from Downcasting section. Downcasting can be done ONLY explicitly.

βœ…

// Explicit downcasting
SObject account = new Account(Name = 'My Account');
Account myAccount = (Account) account;

Standard/Custom Object to Object - casting

Standard/Custom Object to Object

Upcasting

Why it works?

  • Object is a supertype for Account, Contact, and other standard or custom objects.
  • Conversion from Standard/Custom Object to Object is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.

βœ…

// Implicit upcasting
Account account = new Account(Name = 'My Account');
Object myAccount = account;

Object to Standard/Custom Object

Downcasting

Why it works?

  • Object is a supertype for Account, Contact, and other standard or custom objects.
  • Conversion Object to Standard/Custom Object is called Downcasting.
  • As you already know from Downcasting section. Downcasting can be done ONLY explicitly.

βœ…

// Explicit downcasting
Object account = new Account(Name = 'My Account');
Account myAccount = (Account) account;

Primitive Types

Primitive Types - instanceOf

Blob myBlob = Blob.valueof('StringToBlob');
Assert.isTrue(myBlob instanceOf Object);
// Operation instanceOf is always true since an instance of Blob is always an instance of Object

Boolean myBoolean = true;
Assert.isTrue(myBoolean instanceOf Object);
// Operation instanceOf is always true since an instance of Boolean is always an instance of Object

Date myDate = Date.today();
Assert.isTrue(myDate instanceOf Object);
// Operation instanceOf is always true since an instance of Date is always an instance of Object

DateTime myDateTime = DateTime.now();
Assert.isTrue(myDateTime instanceOf Object);
// Operation instanceOf is always true since an instance of Datetime is always an instance of Object

Decimal myDecimal = 1.1;
Assert.isTrue(myDecimal instanceOf Object);
// Operation instanceOf is always true since an instance of Decimal is always an instance of Object

Double myDouble = 1261992;
Assert.isTrue(myDouble instanceOf Object);
// Operation instanceOf is always true since an instance of Double is always an instance of Object

Id myId = '1035U00000ckdinQAX';
Assert.isTrue(myId instanceOf Object);
// Operation instanceOf is always true since an instance of Id is always an instance of Object

Integer myInteger = 12345;
Assert.isTrue(myInteger instanceOf Object);
// Operation instanceOf is always true since an instance of Integer is always an instance of Object

Long myLong = 4271990;
Assert.isTrue(myLong instanceOf Object);
// Operation instanceOf is always true since an instance of Long is always an instance of Object

String myString = 'myString';
Assert.isTrue(myString instanceOf Object);
// Operation instanceOf is always true since an instance of String is always an instance of Object

Account account = new Account();
Assert.isTrue(account instanceOf Object);
//  Operation instanceOf is always true since an instance of Account is always an instance of Object

SObject account = new Account();
Assert.isTrue(account instanceOf Object);
// Operation instanceOf is always true since an instance of SObject is always an instance of Object
Expression is instanceOf
Blob instanceOf Object TRUE βœ…
Boolean instanceOf Object TRUE βœ…
Date instanceOf Object TRUE βœ…
Datetime instanceOf Object TRUE βœ…
Decimal instanceOf Object TRUE βœ…
Double instanceOf Object TRUE βœ…
Id instanceOf Object TRUE βœ…
Integer instanceOf Object TRUE βœ…
Long instanceOf Object TRUE βœ…
String instanceOf Object TRUE βœ…
Account instanceOf Object TRUE βœ…
SObject instanceOf Object TRUE βœ…
  • All Primitive Data Types are instanceOf Object class.
  • Object is a supertype for all primitve types.

Primitive Types - casting

Upcasting

  • Primitive Types can be implicilty cast to Object.

Why?

  • Object is a supertype of all Primitive Types.
  • Conversion from Primitive Type to Object is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.

βœ…

Blob myBlob = Blob.valueof('StringToBlob');
Object myBlobResult = myBlob;

Boolean myBoolean = true;
Object myBooleanResult = myBoolean;

Date myDate = Date.today();
Object myDateResult = myDate;

DateTime myDateTime = DateTime.now();
Object myDateTimeResult = myDateTime;

Decimal myDecimal = 1.1;
Object myDecimalResult = myDecimal;

Double myDouble = 1261992;
Object myDoubleResult = myDouble;

Id myId = '1035U00000ckdinQAX';
Object myIdResult = myId;

Integer myInteger = 12345;
Object myIntegerResult = myInteger;

Long myLong = 4271990;
Object myLongResult = myLong;

String myString = 'myString';
Object myStringResult = myString;

Account account = new Account();
Object myAccountResult = account;

List

List<SObject>

List<SObject> - instanceOf

Assert.isTrue(new List<Account>() instanceOf List<SObject>);
// Operation instanceOf is always true since an instance of List<Account> is always an instance of List<SObject>

Assert.isTrue(new List<SObject>() instanceOf List<Account>);
// Works

Assert.isTrue(new List<SObject>() instanceOf List<Object>);
// Operation instanceOf is always false since an instance of List<SObject> is never an instance of List<Object>
Expression is instanceOf
List<Standard/CustomObject> instanceOf List<SObject> TRUE βœ…
List<SObject> instanceOf List<Standard/CustomObject> TRUE βœ…
List<SObject> instanceOf List<Object> FALSE ❌

🚨

  • List<SObject> is an instance of concrete Standard/Custom Object!
  • List<SObject> is NOT an instance of List<Object>.

List<SObject> - casting

List<SObject> to List<Object>

βœ…

List<SObject> myAccounts = new List<SObject>{ new Account() };
List<Object> myAccountResults = myAccounts;

🚨

  • List<SObject> is NOT an instance of List<Object> (based on instanceOf), but you can still assign List<SObject> to List<Object>. Do not trust instanceOf!
List<Standard/Custom> to List<SObject>

Upcasting

Why it works?

  • List<SObject> is a supertype for List<Standard/Custom>.
  • Conversion from Standard/Custom Object to List<SObject> is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.

βœ…

List<Account> accounts = new List<Account>();
List<SObject> myAccounts = accounts;
List<SObject> to List<Standard/Custom>

Upcasting/Downcasting (?)

🚨

  • List<Standard/CustomObject> is an instance of List<SObject>, and List<SObject> is an instance of List<Standard/CustomObject>.
  • List<Standard/CustomObject> is a supertype for List<SObject>, and List<SObject> is a supertype for List<Standard/CustomObject>.
  • You can do implicit casting.

βœ…

List<SObject> accounts = new List<Account>();
List<Account> myAccounts = accounts;
List<SObject> accounts = new List<SObject>();
List<Account> myAccounts = accounts;

List<Object>

List<Object> - instanceOf

Assert.isTrue(new List<Blob>{ Blob.valueof('StringToBlob') } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Blob>

Assert.isTrue(new List<Boolean>{ true } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Boolean>

Assert.isTrue(new List<Date>{ Date.today() } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Date>

Assert.isTrue(new List<DateTime>{ DateTime.now() } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<DateTime>

Assert.isTrue(new List<Decimal>{ 1.1 } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Decimal>

Assert.isTrue(new List<Double>{ 1261992 } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Double>

Assert.isTrue(new List<Integer>{ 12345 } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Integer>

Assert.isTrue(new List<Long>{ 4271990 } instanceOf List<Object>);
// Operation instanceOf is always true since an instance of List<Blob> is always an instance of List<Long>

Assert.isTrue(new List<SObject>() instanceOf List<Object>);
// Operation instanceOf is always false since an instance of List<SObject> is never an instance of List<Object>
Expression is instanceOf
List<Blob> instanceOf List<Object> TRUE βœ…
List<Boolean> instanceOf List<Object> TRUE βœ…
List<Date> instanceOf List<Object> TRUE βœ…
List<Datetime> instanceOf List<Object> TRUE βœ…
List<Decimal> instanceOf List<Object> TRUE βœ…
List<Double> instanceOf List<Object> TRUE βœ…
List<Id> instanceOf List<Object> TRUE βœ…
List<Integer> instanceOf List<Object> TRUE βœ…
List<Long> instanceOf List<Object> TRUE βœ…
List<String> instanceOf List<Object> TRUE βœ…
List<SObject> instanceOf List<Object> FALSE ❌

🚨

  • SObject is always an instance of Object, hovever List<SObject> is NOT an instance of List<Object>.

List<Object> - casting

  • We can cast List<ConcreteType> to List<Object>,

Why?

  • List<Object> is a supertype of List<ConcreteType>.
  • Conversion from List<ConcreteType> to List<Object> is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.
  • There is no need to cast explicitly by adding (List<Object>).
List<Blob> myBlobs = new List<Blob>{ Blob.valueof('StringToBlob') };
List<Object> myBlobResult = myBlobs;

List<Boolean> myBooleans = new List<Boolean>{ true };
List<Object> myBooleanResult = myBooleans;

List<Date> myDates = new List<Date>{ Date.today() };
List<Object> myDateResult = myDates;

List<DateTime> myDateTimes = new List<DateTime>{ DateTime.now() };
List<Object> myDateTimeResult = myDateTimes;

List<Decimal> myDecimals = new List<Decimal>{ 1.1 };
List<Object> myDecimalResult = myDecimals;

List<Double> myDoubles = new List<Double>{ 1261992 };
List<Object> myDoubleResult = myDoubles;

List<Integer> myIntegers = new List<Integer>{ 12345 };
List<Object> myIntegerResult = myIntegers;

List<Long> myLongs = new List<Long>{ 4271990 };
List<Object> myLongResult = myLongs;

List<String> myStrings = new List<String>{ 'myString' };
List<Object> myStringResult = myStrings;

List<SObject> myAccounts = new List<SObject>{ new Account() };
List<Object> myAccountResults = myAccounts;

🚨

  • List<SObject> is NOT an instance of List<Object> (based on instanceOf), but you can still assign List<SObject> to List<Object>.

List Summary

List casting in Apex is a bit unusual.

What is common:

  • List<ConcreteType> is an instance of List<Object>.
  • List<Object> is a supertype for List<ConcreteType>.

What is unexpected:

  • Based on instanceOf. List<SObject> is not an instance of List<Object>, but you can still assign List<SObject> to List<Object>.
  • You can even assign List<SObject> to List<Object>. Do not trust instanceOf!
  • Even more unexpectedly, List<SObject> is an instance of concrete List<Standard/Custom> Object!

Set

Set<SObject>

Set<SObject> - instanceOf

Assert.isTrue(new Set<Account>() instanceOf Set<SObject>);
//Operation instanceOf is always false since an instance of Set<Account> is never an instance of Set<SObject>

Assert.isTrue(new Set<SObject>() instanceOf Set<Account>);
// Operation instanceOf is always false since an instance of Set<SObject> is never an instance of Set<Account>

Assert.isTrue(new Set<SObject>() instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<SObject> is never an instance of Set<Object>
Expression is instanceOf
Set<Standard/CustomObject> instanceOf Set<SObject> FALSE ❌
Set<SObject> instanceOf Set<Standard/CustomObject> FALSE ❌
Set<SObject> instanceOf Set<Object> FALSE ❌

🚨

  • Set<Standard/CustomObject> is NOT an instance of Set<SObject>.

Set<SObject> - casting

Set<SObject> to Set<Object>
  • You CANNOT cast Set<SObject> to Set<Object>

❌

Set<SObject> myAccounts = new Set<SObject>{ new Account() };
Set<Object> myAccountResults = myAccounts;
// Illegal assignment from Set<SObject> to Set<Object>
Set<SObject> myAccounts = new Set<SObject>{ new Account() };
Set<Object> myAccountResults = (Set<SObject>) myAccounts;
// Illegal assignment from Set<SObject> to Set<Object>
Set<Standard/Custom> to Set<SObject>
  • You CANNOT cast Set<Standard/Custom> to Set<SObject>

❌

Set<Account> accounts = new Set<Account>();
Set<SObject> myAccounts = accounts;
// Illegal assignment from Set<Account> to Set<SObject>
Set<Account> accounts = new Set<Account>();
Set<SObject> myAccounts = (Set<Account>) accounts;
// Illegal assignment from Set<Account> to Set<SObject>
Set<SObject> to Set<Standard/Custom>
  • You CANNOT cast Set<SObject> to Set<Standard/Custom>

❌

Set<SObject> accounts = new Set<Account>();
// Illegal assignment from Set<Account> to Set<SObject>
Set<SObject> accounts = new Set<SObject>();
Set<Account> myAccounts = accounts;
// Illegal assignment from Set<SObject> to Set<Account>

Set<Object>

Set<Object> - instanceOf

Assert.isTrue(new Set<Blob>{ Blob.valueof('StringToBlob') } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Blob> is never an instance of Set<Object>

Assert.isTrue(new Set<Boolean>{ true } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Boolean> is never an instance of Set<Object>

Assert.isTrue(new Set<Date>{ Date.today() } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Date> is never an instance of Set<Object>

Assert.isTrue(new Set<DateTime>{ DateTime.now() } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<DateTime> is never an instance of Set<Object>

Assert.isTrue(new Set<Decimal>{ 1.1 } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Decimal> is never an instance of Set<Object>

Assert.isTrue(new Set<Double>{ 1261992 } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Double> is never an instance of Set<Object>

Assert.isTrue(new Set<Integer>{ 12345 } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Integer> is never an instance of Set<Object>

Assert.isTrue(new Set<Long>{ 4271990 } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<Long> is never an instance of Set<Object>

Assert.isTrue(new Set<String>{ 'myString' } instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<String> is never an instance of Set<Object>

Assert.isTrue(new Set<SObject>() instanceOf Set<Object>);
// Operation instanceOf is always false since an instance of Set<SObject> is never an instance of Set<Object>
Expression is instanceOf
Set<Blob> instanceOf Set<Object> FALSE ❌
Set<Boolean> instanceOf Set<Object> FALSE ❌
Set<Date> instanceOf Set<Object> FALSE ❌
Set<Datetime> instanceOf Set<Object> FALSE ❌
Set<Decimal> instanceOf Set<Object> FALSE ❌
Set<Double> instanceOf Set<Object> FALSE ❌
Set<Id> instanceOf Set<Object> FALSE ❌
Set<Integer> instanceOf Set<Object> FALSE ❌
Set<Long> instanceOf Set<Object> FALSE ❌
Set<String> instanceOf Set<Object> FALSE ❌
Set<SObject> instanceOf Set<Object> FALSE ❌
  • Other than List, Set<Object> is NOT a supertype for Set<ConcreteType>.

Set<Object> - casting

  • We CANNOT cast Set<ConcreteType> to Set<Object>,
Set<Blob> mySetBlobs = new Set<Blob>{ Blob.valueof('StringToBlob') };
Set<Object> myBlobs = mySetBlobs;
// Illegal assignment from Set<Blob> to Set<Object>

Set<Boolean> mySetBooleans = new Set<Boolean>{ true };
Set<Object> myBooleans = mySetBooleans;
// Illegal assignment from Set<Boolean> to Set<Object>

Set<Date> mySetDates = new Set<Date>{ Date.today() };
Set<Object> myDates = mySetDates;
// Illegal assignment from Set<Date> to Set<Object>

Set<DateTime> mySetDateTimes = new Set<DateTime>{ DateTime.now() };
Set<Object> myDateTimes = mySetDateTimes;
// Illegal assignment from Set<DateTime> to Set<Object>

Set<Decimal> mySetDecimals = new Set<Decimal>{ 1.1 };
Set<Object> myDecimals = mySetDecimals;
// Illegal assignment from Set<Decimal> to Set<Object>

Set<Double> mySetDoubles = new Set<Double>{ 1261992 };
Set<Object> myDoubles = mySetDoubles;
// Illegal assignment from Set<Double> to Set<Object>

Set<Integer> mySetIntegers = new Set<Integer>{ 12345 };
Set<Object> myIntegers = mySetIntegers;
// Illegal assignment from Set<Integer> to Set<Object>

Set<Long> mySetLongs = new Set<Long>{ 4271990 };
Set<Object> myLongs = mySetLongs;
// Illegal assignment from Set<Long> to Set<Object>

Set<String> mySetStrings = new Set<String>{ 'myString' };
Set<Object> myStrings = mySetStrings;
// Illegal assignment from Set<String> to Set<Object>

Set<SObject> myAccounts = new Set<SObject>{ new Account() };
Set<Object> myAccountResults = myAccounts;
// Illegal assignment from Set<SObject> to Set<Object>

Even if you explicitly add casting (Set<Object>) it will not work.

Set<Blob> mySetBlobs = new Set<Blob>{ Blob.valueof('StringToBlob') };
Set<Object> myBlobs = (Set<Object>) mySetBlobs;
// Incompatible types since an instance of Set<Blob> is never an instance of Set<Object>

Set<Boolean> mySetBooleans = new Set<Boolean>{ true };
Set<Object> myBooleans = (Set<Object>) mySetBooleans;
// Incompatible types since an instance of Set<Boolean> is never an instance of Set<Object>

Set<Date> mySetDates = new Set<Date>{ Date.today() };
Set<Object> myDates = (Set<Object>) mySetDates;
// Incompatible types since an instance of Set<Date> is never an instance of Set<Object>

Set<DateTime> mySetDateTimes = new Set<DateTime>{ DateTime.now() };
Set<Object> myDateTimes = (Set<Object>) mySetDateTimes;
// Incompatible types since an instance of Set<DateTime> is never an instance of Set<Object>

Set<Decimal> mySetDecimals = new Set<Decimal>{ 1.1 };
Set<Object> myDecimals = (Set<Object>) mySetDecimals;
// Incompatible types since an instance of Set<Decimal> is never an instance of Set<Object>

Set<Double> mySetDoubles = new Set<Double>{ 1261992 };
Set<Object> myDoubles = (Set<Object>) mySetDoubles;
// Incompatible types since an instance of Set<Double> is never an instance of Set<Object>

Set<Integer> mySetIntegers = new Set<Integer>{ 12345 };
Set<Object> myIntegers = (Set<Object>) mySetIntegers;
// Incompatible types since an instance of Set<Integer> is never an instance of Set<Object>

Set<Long> mySetLongs = new Set<Long>{ 4271990 };
Set<Object> myLongs = (Set<Object>) mySetLongs;
// Incompatible types since an instance of Set<Long> is never an instance of Set<Object>

Set<String> mySetStrings = new Set<String>{' myString' };
Set<Object> myStrings = (Set<Object>) mySetStrings;
// Incompatible types since an instance of Set<String> is never an instance of Set<Object>

Set<SObject> myAccounts = new Set<SObject>{ new Account() };
Set<Object> myAccountResults = (Set<Object>) myAccounts;
// Incompatible types since an instance of Set<SObject> is never an instance of Set<Object>

Set Summary

  • Other than List, Set<Object> is NOT a supertype for Set<ConcreteType>.

Map

Map<SObject>

Map<SObject> - instanceOf

I skipped cases where SObject is a key. SObject should never be a key in the Map.

Assert.isTrue(new Map<Object, Account>() instanceof Map<Object, Object>);
// Operation instanceof is always true since an instance of Map<Object,Account> is always an instance of Map<Object,Object>

Assert.isTrue(new Map<Object, Account>() instanceof Map<Object, SObject>);
// Operation instanceof is always true since an instance of Map<Object,Account> is always an instance of Map<Object,SObject>
Key Type Value Type Key Type Value Type Is instanceOf
Object Account Object Object TRUE βœ…
Object Account Object SObject TRUE βœ…
  • Map<Object, Account> is an instance of Map<Object, Object>, which means that Map<Object, Object> is a supertype of Map<Object, Account> .
  • Map<Object, Account> is an instance of Map<Object, SObject>, which means that Map<Object, SObject> is a supertype of Map<Object, Account> .

Map<SObject> - casting

Upcasting

Why it works?

  • Map<Object, Object> is a supertype for Map<Object, Standard/CustomObject>.
  • Conversion from Map<Object, Standard/CustomObject> to Map<Object, Object> is called Upcasting.
  • As you already know from Upcasting section. Upcasting can be done explicitly or implicitly.

βœ…

Map<Object, Object> myMap = new Map<Object, Account>();

Map<Id, Object> myMap2 = new Map<Id, Account>();
Map<Object, SObject> myMap = new Map<Object, Account>();

Map<Id, SObject> myMap2 = new Map<Id, Account>();

Downcasting

❌

Map<Object, Object> myMap = new Map<Object, Account>();
// Illegal assignment from Map<Object,Object> to Map<Object,Account>
Map<Object, Account> myMap = new Map<Object, SObject>();
// Illegal assignment from Map<Object,SObject> to Map<Object,Account>

Even explicit casting will not work. The error is different.

Map<Object, Account> myMap = (Map<Object, Account>) new Map<Object, Object>();
//System.TypeException: Invalid conversion from runtime type Map<ANY,ANY> to Map<ANY,Account>
Map<Object, Account> myMap = (Map<Object, Account>) new Map<Object, SObject>();
// System.TypeException: Invalid conversion from runtime type Map<ANY,SObject> to Map<ANY,Account>

How to fix Map downasting?

βœ…

SObjectType ofObject = Account.SObjectType;

Map<Id, SObject> idToSObject = (Map<Id, SObject>) Type.forName('Map<Id, ' + ofObject  + ' >').newInstance();

Map<Id, Account> idToAccount = (Map<Id, Account>) idToSObject;
String ofObject = 'Account'

Map<Id, SObject> idToSObject = (Map<Id, SObject>) Type.forName('Map<Id, ' + ofObject  + ' >').newInstance();

Map<Id, Account> idToAccount = (Map<Id, Account>) idToSObject;

Map<Object>

Map<Object> - instanceOf

Assert.isTrue(new Map<String, String>() instanceOf Map<Object, Object>);
// Operation instanceOf is always false since an instance of Map<String,String> is never an instance of Map<Object,Object>

Assert.isTrue(new Map<String, String>() instanceOf Map<String, Object>);
// Operation instanceOf is always true since an instance of Map<String,String> is always an instance of Map<String,Object>

Assert.isTrue(new Map<String, String>() instanceOf Map<Object, String>);
// Operation instanceOf is always false since an instance of Map<String,String> is never an instance of Map<Object,String>

Assert.isTrue(new Map<String, Object>() instanceOf Map<Object, Object>);
// Operation instanceOf is always false since an instance of Map<String,Object> is never an instance of Map<Object,Object>

Assert.isTrue(new Map<String, Object>() instanceOf Map<Object, String>);
// Operation instanceOf is always false since an instance of Map<String,Object> is never an instance of Map<Object,String>

Assert.isTrue(new Map<String, Object>() instanceOf Map<String, String>);
// FALSE

Assert.isTrue(new Map<Object, String>() instanceOf Map<Object, Object>);
// Operation instanceOf is always true since an instance of Map<Object,String> is always an instance of Map<Object,Object>

Assert.isTrue(new Map<Object, String>() instanceOf Map<String, Object>);
// Operation instanceOf is always false since an instance of Map<Object,String> is never an instance of Map<String,Object>

Assert.isTrue(new Map<Object, String>() instanceOf Map<String, String>);
// Operation instanceOf is always false since an instance of Map<Object,String> is never an instance of Map<String,String>
Key Type Value Type Key Type Value Type Is Instance Of
String String Object Object FALSE ❌
String String String Object TRUE βœ…
String String Object String FALSE ❌
String Object Object Object FALSE ❌
String Object Object String FALSE ❌
String Object String String FALSE ❌
Object String Object Object TRUE βœ…
Object String String Object FALSE ❌
Object String String String FALSE ❌

Maps are the same instance only in the following cases:

  • new Map<MyType, MyType>() instanceOf new Map<MyType, Object>
  • new Map<Object, MyType>() instanceOf new Map<Object, Object>

Key Type must be the same.

Map<Object> - casting

❌

Map<Object, Object> objectObjectStringString = new Map<String, String>();
// Illegal assignment from Map<String,String> to Map<Object,Object>

Map<Object, String> objectStringStringString = new Map<String, String>();
// Illegal assignment from Map<String,String> to Map<Object,String>

Map<Object, Object> objectObjectStringObject = new Map<String, Object>();
// Illegal assignment from Map<String,Object> to Map<Object,Object>

Map<Object, String> objectStringStringObject = new Map<String, Object>();
// Illegal assignment from Map<String,Object> to Map<Object,String>

Map<String, String> stringStringStringObject = new Map<String, Object>();
// Illegal assignment from Map<String,Object> to Map<String,String>

Map<String, Object> stringObjectObjectString = new Map<Object, String>();
// Illegal assignment from Map<Object,String> to Map<String,Object>

Map<String, String> StringStringObjectString = new Map<Object, String>();
// Illegal assignment from Map<Object,String> to Map<String,String>

βœ…

Map<String, Object> stringObjectStringString = new Map<String, String>();
Map<Object, Object> objectObjectObjectString = new Map<Object, String>();

You can cast implicitly only when:

  • new Map<MyType, MyType>() instanceOf new Map<MyType, Object>
  • new Map<Object, MyType>() instanceOf new Map<Object, Object>

Map Summary

Iterable

Starting from Summer 23', Set implements Iterable interface as List does.

Iterable List

Iterable List - instanceOf

Assert.isTrue(new List<Object>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of List<Object> is always an instance of System.Iterable<Object>
Assert.isTrue(new List<Blob>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Boolean>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Date>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Datetime>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Decimal>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Double>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Id>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Integer>() instanceOf Iterable<Object>);
Assert.isTrue(new List<Long>() instanceOf Iterable<Object>);
Assert.isTrue(new List<String>() instanceOf Iterable<Object>);
Assert.isTrue(new List<SObject>() instanceOf Iterable<Object>);

Not surprisingly, a List of concrete types is also an instance of Iterable<Object>.

Expression is instanceOf Iterable<Object>
List<Blob> instanceOf Iterable<Object> TRUE βœ…
List<Boolean> instanceOf Iterable<Object> TRUE βœ…
List<Date> instanceOf Iterable<Object> TRUE βœ…
List<Datetime> instanceOf Iterable<Object> TRUE βœ…
List<Decimal> instanceOf Iterable<Object> TRUE βœ…
List<Double> instanceOf Iterable<Object> TRUE βœ…
List<Id> instanceOf Iterable<Object> TRUE βœ…
List<Integer> instanceOf Iterable<Object> TRUE βœ…
List<Long> instanceOf Iterable<Object> TRUE βœ…
List<String> instanceOf Iterable<Object> TRUE βœ…
List<SObject> instanceOf Iterable<Object> TRUE βœ…
Assert.isTrue(new List<Object>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of List<Object> is always an instance of System.Iterable<Object>

Assert.isFalse(new Set<Object>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Object> is always an instance of System.Iterable<Object>
  • Instance of List<Object> and Set<Object> are always an instance of System.Iterable<Object>.

Iterable List - casting

βœ…

Iterable<Object> myIterableObjects = new List<Object>();

❌

Iterable<Object> myIterableBlobs = new List<Blob>();
// Illegal assignment from List<Blob> to System.Iterable<Object>

Iterable<Object> myIterableBooleans = new List<Boolean>();
// Illegal assignment from List<Boolean> to System.Iterable<Object>

Iterable<Object> myIterableDates = new List<Date>();
// Illegal assignment from List<Date> to System.Iterable<Object>

Iterable<Object> myIterableDatetimes = new List<Datetime>();
// Illegal assignment from List<Datetime> to System.Iterable<Object>

Iterable<Object> myIterableDecimals = new List<Decimal>();
// Illegal assignment from List<Decimal> to System.Iterable<Object>

Iterable<Object> myIterableDoubles = new List<Double>();
// Illegal assignment from List<Double> to System.Iterable<Object>

Iterable<Object> myIterableIds = new List<Id>();
// Illegal assignment from List<Id> to System.Iterable<Object>

Iterable<Object> myIterableIntegers = new List<Integer>();
// Illegal assignment from List<Integer> to System.Iterable<Object>

Iterable<Object> myIterableLongs = new List<Long>();
// Illegal assignment from List<Long> to System.Iterable<Object>

Iterable<Object> myIterableStrings = new List<String>();
// Illegal assignment from List<String> to System.Iterable<Object>

Iterable<Object> myIterableSObjects = new List<SObject>();
// Illegal assignment from List<SObject> to System.Iterable<Object>

It's really interesting.

e.g List<String> is an instance of Iterable<Object>, but you CANNOT use Iterable<Object> as a supertype.

❌

Iterable<Object> myIterableStrings = new List<String>();

βœ…

You need to assign List<String> to List<Object> and after it to Iterable<Object>.

List<Object> myStrings = new List<String>();
Iterable<Object> myIterableObjects = myStrings;

Iterable Set

Iterable Set - instanceOf

Assert.isTrue(new Set<Blob>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Blob> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Boolean>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Boolean> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Date>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Date> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Datetime>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Datetime> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Decimal>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Decimal> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Double>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Double> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Id>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Id> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Integer>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Integer> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<Long>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<Long> is always an instance of System.Iterable<Object>

Assert.isTrue(new Set<String>() instanceOf Iterable<Object>);
// Operation instanceOf is always true since an instance of Set<String> is always an instance of System.Iterable<Object>

Assert.isFalse(new Set<SObject>() instanceOf Iterable<Object>);
Expression is instanceOf
Set<Blob> instanceOf Iterable<Object> TRUE βœ…
Set<Boolean> instanceOf Iterable<Object> TRUE βœ…
Set<Date> instanceOf Iterable<Object> TRUE βœ…
Set<Datetime> instanceOf Iterable<Object> TRUE βœ…
Set<Decimal> instanceOf Iterable<Object> TRUE βœ…
Set<Double> instanceOf Iterable<Object> TRUE βœ…
Set<Id> instanceOf Iterable<Object> TRUE βœ…
Set<Integer> instanceOf Iterable<Object> TRUE βœ…
Set<Long> instanceOf Iterable<Object> TRUE βœ…
Set<String> instanceOf Iterable<Object> TRUE βœ…
Set<SObject> instanceOf Iterable<Object> FALSE ❌
  • An interesting thing is that you're getting an error Operation instanceOf is always true....
  • Set<ConcreteType> is also an instance of Iterable<Object>, but not Set<SObject>.

Iterable Set - casting

βœ…

Iterable<Object> myIterableObjects = new Set<Object>();

βœ…

Iterable<Object> myIterableBlobs = new Set<Blob>();
Iterable<Object> myIterableBooleans = new Set<Boolean>();
Iterable<Object> myIterableDates = new Set<Date>();
Iterable<Object> myIterableDatetimes = new Set<Datetime>();
Iterable<Object> myIterableDecimals = new Set<Decimal>();
Iterable<Object> myIterableDoubles = new Set<Double>();
Iterable<Object> myIterableIds = new Set<Id>();
Iterable<Object> myIterableIntegers = new Set<Integer>();
Iterable<Object> myIterableLongs = new Set<Long>();
Iterable<Object> myIterableStrings = new Set<String>();
Iterable<Object> myIterableSObjects = new Set<SObject>();
// Illegal assignment from Set<SObject> to System.Iterable<Object>
  • You CAN use Iterable<Object> as a supertype for Set, which you CANNOT do with a List.
  • You CANNOT assign Set<SObject> to Iterable<Object>.

Summary

It's quite a big deal. Let's check an example:

public interface Filter {
    Filter isIn(Iterable<Object> inList);
}

public class MyFilter implements Filter {
    public Filter isIn(Iterable<Object> inList) {
        return this;
    }
}

❌

MyFilter myFilter = new MyFilter();

myFilter.isIn(new List<String>{ 'Test1', 'Test2' });
// Method does not exist or incorrect signature: void isIn(List<String>) from the type Filter

myFilter.isIn(new List<Decimal>{ 1, 2 });
// Method does not exist or incorrect signature: void isIn(List<Decimal>) from the type Filter

βœ…

MyFilter myFilter = new MyFilter();

myFilter.isIn(new List<Object>{ 1, 2, 'Test1', 'Test2' });
myFilter.isIn(new Set<String>{ 'Test1', 'Test2 '});
myFilter.isIn(new Set<Decimal>{ 1, 2 });
myFilter.isIn(new Set<Object>{ 1, 2, 'Test1', 'Test2 ' });

How to fix it?

🚨

  • You need two methods (isIn(Iterable<Object> inList) and isIn(List<Object> inList)) in the interface that will be covered by one method (isIn(Iterable<Object> inList) in concrete class!
public interface Filter {
    Filter isIn(Iterable<Object> inList);
    Filter isIn(List<Object> inList);
}

public class MyFilter implements Filter {
    public Filter isIn(Iterable<Object> inList) {
        return this;
    }
}

Iterable Summary

  • List
    • Instance of List<Object> and Set<Object> are always an instance of System.Iterable<Object>.
    • You CANNOT use Iterable<Object> as a supertype for List<ConcreteType>. You need to assign List<ConcreteType> to List<Object> and after it to Iterable<Object>.
  • Set
    • Set<ConcreteType> is instance of Iterable<Object>.
    • Set<Sobject> is NOT instance of Set<SObject>.

Casting Rules

Cast to everything

The problem with the solution below is performance.

βœ…

Map<Object, SObject> someKeyToRecord = new Map<Object, SObject>{
    'My Account' => new Account(Name = 'My Account')
};

Map<String, Account> nameToAccount = (Map<String, Account>) JSON.deserialize(JSON.serialize(someKeyToRecord), Map<String, Account>.class);

Casting Cheat Sheet

Do Not Trust instanceOf

Based on the type system is broken with regards to collections:

Pretty much the entire "Type" system that governs Maps, Sets, and Lists is broken. Do not trust instanceOf, use your own logical assessment to determine if something is safe or not.

As shown in the post, there are cases where instanceOf does not work correctly.

e.g

List<SObject> and List<Object>

instanceOf says that "List<SObject> is never an instance of List<Object>", but you can assign List<SObject> to List<Object>.

❌

Assert.isFalse(new  List<SObject>() instanceOf List<Object>);
// Operation instanceOf is always false since an instance of List<SObject> is never an instance of List<Object>

βœ…

List<Object> sObjects = new List<SObject>();

List<ConcreteType> and Iterable<Object>

instanceOf says that List<ConcreteType> is an instance of Iterable<Object>, but you CANOT assign List<ConcreteType> to Iterable<Object>.

❌

Iterable<Object> myIterableStrings = new List<String>();

βœ…

You need to assign List<String> to List<Object> and after it to Iterable<Object>.

List<Object> myStrings = new List<String>();
Iterable<Object> myIterableObjects = myStrings;

SObject Casting

  • SObject is a supertype for:
    • all standard objects (Account, Contact, etc.)
    • all custom objects (MyCustomObject__c)
SObject account = new Account(Name = 'My Account');
SObject myObject = new MyCustomObject__c();
  • Casting from Standard/Custom Object to SObject is called upcasting and can be implicitly.
SObject account = new Account(Name = 'My Account');
  • Casting from SObject to Standard/Custom Object is called downcasting and it needs to be explicit.
SObject account = new Account(Name = 'My Account');
Account myAccount = (Account) account;
  • SObject is instance of Object. Object is a supertype for SObject.
Object account = new Account(Name = 'My Account');
  • Casting from SObject to Object is called upcasting and can be implicit.
Object account = new Account(Name = 'My Account');
  • Casting from Object to SObject is called downcasting and it needs to be explicit.
Object account = new Account(Name = 'My Account');
SObject myAccount = (SObject) account;

Object Casting

  • Object is a supertype for:
    • all standard objects
    • all custom objects
    • all apex classes
    • all collections (List, Set and Map)
    • all apex types (Integer, String, Boolean)

Primitive Types Casting

  • All Primitive Data Types are instanceOf Object. Object is a supertype for all primitve types.
  • Casting from Primitive Data Types to Object is called upcasting and can be implicit.
String myString = 'myString';
Object myStringResult = myString;

List Casting

  • All List<ConcreteType> are instance of List<Object>. List<Object> is a supertype of List<ConcreteType>.
  • Based on instanceOf method List<SObject> is NOT an instance of List<Object>, but still you can assign List<SObject> to List<Object>. Do not trust instanceOf.
  • Casting from List<ConcreteType> to List<Object> is called upcasting and can be implicit.
List<String> myStrings = new List<String>{ 'myString' };
List<Object> myStringResult = myStrings;

List<SObject> myAccounts = new List<SObject>{ new Account() };
List<Object> myAccountResults = myAccounts;
  • List<SObject> is a supertype for List<Standard/Custom>.
List<Account> accounts = new List<Account>();
List<SObject> myAccounts = accounts;

🚨

  • List<Standard/Custom> is a supertype for List<SObject>.
List<SObject> accounts = new List<Account>();
List<Account> myAccounts = accounts;
List<SObject> accounts = new List<SObject>();
List<Account> myAccounts = accounts;

Set Casting

  • Other than List, Set<Object> is NOT a supertype for Set<ConcreteType>.
  • You CANNOT cast Set<ConcreteType> to Set<Object>.
Set<String> mySetStrings = new Set<String>{' myString' };
Set<Object> myStrings = (Set<Object>) mySetStrings;
// Incompatible types since an instance of Set<String> is never an instance of Set<Object>

Map Casting

  • Map<Object, Account> is instance of Map<Object, Object>, it means that Map<Object, Object> is a supertype for Map<Object, Account> .
  • Map<Object, Account> is instance of Map<Object, SObject>, it means that Map<Object, SObject> is a supertype for Map<Object, Account> .
Map<Object, Object> myMap = new Map<Object, Account>();
Map<Id, Object> myMap2 = new Map<Id, Account>();

Map<Object, SObject> myMap = new Map<Object, Account>();
Map<Id, SObject> myMap2 = new Map<Id, Account>();
  • To fix System.TypeException: Invalid conversion from runtime type Map<ANY,SObject> to Map<ANY,Account> dynamic Map initiation is needed.
SObjectType ofObject = Account.SObjectType;

Map<Id, SObject> idToSObject = (Map<Id, SObject>) Type.forName('Map<Id, ' + ofObject  + ' >').newInstance();

Map<Id, Account> idToAccount = (Map<Id, Account>) idToSObject;

Iterable Casting

  • List
    • Instance of List<Object> and Set<Object> are always an instance of System.Iterable<Object>.
    • You CANNOT use Iterable<Object> as a supertype for List<ConcreteType>. You need to assign List<ConcreteType> to List<Object> and after it to Iterable<Object>.
List<Object> myStrings = new List<String>();
Iterable<Object> myIterableObjects = myStrings;
  • Set
    • Set<ConcreteType> is instance of Iterable<Object>, but Set<SObject> is NOT instance of Iterable<SObject>.
Iterable<Object> myIterableObjects = new Set<Object>();

Resources