Skip to main content
replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type ErasureType Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After re-reading (again), noticed that my link to StackOverflow used angle brackets that needed backticks to be rendered
Source Link
Derek F
  • 64.1k
  • 15
  • 55
  • 104

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

Added example of List up-casting in Apex that results in a runtime exception.
Source Link
Daniel Ballinger
  • 103k
  • 40
  • 275
  • 601

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode.

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

After doing a deeper dive with google, I think I have the answer.

It turns out that this is a behavior defined by Java to ensure type safety. In Java, a Set<String> is a 'Generic' collection. Generics in Java cannot be up-cast (generics are not covariant) because (in part) Java erases the type information (of generics) upon compilation to bytecode (known as Type Erasure).

There are several resources that I found that explain this:

Because a Set<String> in Apex is implemented as a Java Set<String> (using the HashSet data structure, though that bit isn't important), Apex is subject to this restriction of Java.

So why are Lists and Maps in Apex are just fine with up-casting?

E.g. The following will compile and then fail at runtime in Apex.

List<Sobject> sobjs = (List<Sobject>)(new List<Account>());
sobjs.add(new Account());
sobjs.add(new Contact());

System.TypeException: Collection store exception adding Contact to List

I think this speaks to how Salesforce implements these two collection types.

Salesforce doesn't directly mention how Lists and Maps are implemented in the documentation (unlike the documentation for Sets), but based on how we are able to declare Lists like this

String[] stringList = new List<String>();

And access list indices like this

String result = stringList[0];

I'd have to say that I think Lists in Apex are actually Java arrays (which are covariant, and therefore can be up-cast) with some extra bits to hide the fact that Java arrays have a static size.

Maps are...I have no idea.

The following snippet works

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Id, Object> testMap2 = (Map<Id, Object>)testMap1;

While this snippet won't compile

Map<Id, String> testMap1 = new Map<Id, String>();
Map<Object, String> testMap2 = (Map<Object, String>)testMap1;

The methods exposed by the Java Map interface look very similar to the Map methods that Salesforce offers. Perhaps Apex Maps end up using Java type wldcards, or are a custom implementation that stores the keys in a set, and the values in an array (and has something to map keys to indices in the values array).

clarified that Java's type-erasure is chiefy applied to generics (rather than, say, lone Integers)
Source Link
Derek F
  • 64.1k
  • 15
  • 55
  • 104
Loading
Source Link
Derek F
  • 64.1k
  • 15
  • 55
  • 104
Loading