1

I have read this SO post, but I am asking a slightly different question:

I would like to be able to write a method that can accept a Set with any parameterized type.

e.g. myMethod(Set<Object> genericSet)

If I were wanting to do the same thing with a List, then I could using List<Object> because the following is possible:

List<Object> genericList = new List<String>();

In other words List<Object> can act as an abstraction of List<String>.

However, I can't use Set<Object> as a method parameter and expect to be able to pass in Set<String> because the following throws a compilation error:

Set<Object> genericSet = new Set<String>();

I'm not sure why this is. Possibly something to do with the fact that different types have different hashCode() functions?

Alternative

As an alternative, I could just have my parameter be of type Object, which would allow me to pass in any type of Set<?>. However, the problem with this is that I need to check that the argument passed in is indeed a Set of some sort. Furthermore, if it is, then because generic sets aren't allowed, I would need to know the exact type so that I can cast it to the correct set type.

I can't use myArg instanceof Set because Set has to has some sort of parameterized type.

And because of the issue I outlined above, I can't use myArg instanceof Set<Object> because this will return false for everything except when the parameterized type really is Object.

Does anyone know how I might be able to get some sort of generic behaviour for Sets?

lemming
  • 473
  • 1
  • 4
  • 16

1 Answers1

3

The type system is oddly broken in a number of ways that they're also broken in Java, in addition to a unique set of problems in Apex that Phil W linked to.

However, if you're interested in a solution, you can indeed use sets and lists interchangeably through the use of Iterable. Unfortunately, it will require a cast every time you want to use it. Here's an Execute Anonymous script you can check out.

void printValues(Iterable<Object> v) {
    Object[] values = new Object[0];
    Iterator<Object> it = v.iterator();
    while(it.hasNext()) {
        values.add(it.next());
    }
    System.debug(values);
}
Set<String> setOfString = new Set<String>{'hello','world'};
printValues((Iterable<Object>)setOfString);
List<String> listOfString = new List<String>{'hello','world'};
printValues((Iterable<Object>)listOfString);

Notice how we can extract values from a list or set of any time if we cast it to Iterable first. Unfortunately, we still can't get to a "concrete" type dynamically, but you can use this on a case-by-case basis to work within the limitations of Apex.

sfdcfox
  • 489,769
  • 21
  • 458
  • 806
  • thanks very much for your comment. Although what I was trying to say and probably expressing badly is that I only wanted to use Sets. So I need to internally check that the Object passed into the method is a Set (of any type). I don't believe this is possible because you have to include the parameterised type, and Set only works when using instance of for Sets of Objects and not Sets for any other type. – lemming Apr 30 '22 at 12:56
  • @lemming You can't cast Sets between different types, unfortunately. That's just how they work. Iterable is your only real path forward. – sfdcfox Apr 30 '22 at 17:46