Set
implements the Iterable Interface based on the latest Salesforce release (API 58).
I tried to refactor my code to make it simpler and use Iterable<Object>
as a supertype for a List<Object>
and Set<Object>
.
Step 1
I tried do do something like that:
public interface Filter {
Filter isIn(Iterable<Object> inList);
}
public class QFilter implements Filter {
public Filter isIn(Iterable<Object> inList) {
return this;
}
}
Filter myFilter = new QFilter();
myFilter.isIn(new List<String>{ 'Test1', 'Test2' }); // ERROR: Method does not exist or incorrect signature: void isIn(List<String>) from the type Filter
myFilter.isIn(new List<Decimal>{ 1, 2 }); // ERROR: Method does not exist or incorrect signature: void isIn(List<Decimal>) from the type Filter
myFilter.isIn(new List<Object>{ 1, 2, 'Test1', 'Test2' }); // WORKS AS EXPECTED
myFilter.isIn(new Set<String>{ 'Test1', 'Test2 '}); // WORKS AS EXPECTED
myFilter.isIn(new Set<Decimal>{ 1, 2 }); // WORKS AS EXPECTED
myFilter.isIn(new Set<Object>{ 1, 2, 'Test1', 'Test2 ' }); // WORKS AS EXPECTED
I got Method does not exist or incorrect signature
errors.
Step 2
In the next step I added isIn(List<Object> inList)
, which make my code working.
public interface Filter {
Filter isIn(Iterable<Object> inList);
Filter isIn(List<Object> inList); // NEW METHOD
}
public class QFilter implements Filter {
// Method below covers isIn(Iterable<Object>) and isIn(List<Object>)
public Filter isIn(Iterable<Object> inList) {
return this;
}
}
Filter myFilter = new QFilter();
myFilter.isIn(new List<String>{ 'Test1', 'Test2' }); // WORKS AS EXPECTED
myFilter.isIn(new List<Decimal>{ 1, 2 }); // WORKS AS EXPECTED
myFilter.isIn(new List<Object>{ 1, 2, 'Test1', 'Test2' }); // WORKS AS EXPECTED
myFilter.isIn(new Set<String>{ 'Test1', 'Test2 '}); // WORKS AS EXPECTED
myFilter.isIn(new Set<Decimal>{ 1, 2 }); // WORKS AS EXPECTED
myFilter.isIn(new Set<Object>{ 1, 2, 'Test1', 'Test2 ' }); // WORKS AS EXPECTED
Step 3
I checked instanceof
for all of the examples.
Map<String, Boolean> caseToIsInstance = new Map<String, Boolean>{
'List<String> instanceOf List<Object>' => true, // Operation instanceof is always true since an instance of List<String> is always an instance of List<Object>
'List<Decimal> instanceOf List<Object>' => true, // Operation instanceof is always true since an instance of List<Decimal> is always an instance of List<Object>
'List<Object> instanceOf Iterable<Object>' => true, // Operation instanceof is always true since an instance of List<Object> is always an instance of System.Iterable<Object>
'List<String> instanceOf Iterable<Object>' => new List<String>() instanceOf Iterable<Object>,
'List<Decimal> instanceOf Iterable<Object>' => new List<Decimal>() instanceOf Iterable<Object>,
'Set<String> instanceOf Set<Object>' => false, // Operation instanceof is always false since an instance of Set<String> is never an instance of Set<Object>
'Set<Decimal> instanceOf Set<Object>' => false, // Operation instanceof is always false since an instance of Set<Decimal> is never an instance of Set<Object>
'Set<Object> instanceOf Iterable<Object>' => true, // Operation instanceof is always true since an instance of List<Object> is always an instance of System.Iterable<Object>
'Set<String> instanceOf Iterable<Object>' => true, // Operation instanceof is always true since an instance of Set<String> is always an instance of System.Iterable<Object>
'Set<Decimal> instanceOf Iterable<Object>' => true // Operation instanceof is always true since an instance of Set<Decimal> is always an instance of System.Iterable<Object>
};
System.debug(LoggingLevel.DEBUG, ': ' + JSON.SerializePretty(caseToIsInstance));
{
"Set<Decimal> instanceOf Iterable<Object>" : true,
"Set<String> instanceOf Iterable<Object>" : true,
"Set<Object> instanceOf Iterable<Object>" : true,
"Set<Decimal> instanceOf Set<Object>" : false,
"Set<String> instanceOf Set<Object>" : false,
"List<Decimal> instanceOf Iterable<Object>" : true,
"List<String> instanceOf Iterable<Object>" : true,
"List<Object> instanceOf Iterable<Object>" : true,
"List<Decimal> instanceOf List<Object>" : true,
"List<String> instanceOf List<Object>" : true
}
But still e.g List<String>
cannot be assigned to Iterable<Object>
.
Iterable<Object> test1 = new Set<Decimal>(); // WORKS
Iterable<Object> test2 = new Set<String>(); // WORKS
Iterable<Object> test3 = new Set<Object>(); // WORKS
Iterable<Object> test4 = new List<Decimal>(); // Illegal assignment from List<Decimal> to System.Iterable<Object>
Iterable<Object> test5 = new List<String>(); // Illegal assignment from List<String> to System.Iterable<Object>
Iterable<Object> test6 = new List<Object>(); // WORKS
List<Object> test7 = new List<Decimal>(); // WORKS
List<Object> test8 = new List<String>(); // WORKS
Conclusion & Question
The Iterable<Object>
and List<ConcreteType>
have weird behavior.
List<String>
is instance of Iterable<Object>
, but still those types are not compatible (cannot be assigned directly).
It looks that List<String>
needs to be converted to List<Object>
and after assignment to Iterable<Object>
will work.
// ***** LIST *****
// DOES NOT WORK
Iterable<Object> iterableList = new List<String>();
// WORKS
List<Object> genericList = new List<String>();
Iterable<Object> iterableList = genericList;
// ***** SET *****
// WORKS
Iterable<Object> iterableSet = new Set<String>()
How is is possible? What am I missing? Why Set have different behavior? Is it just Apex thing?