It would be really useful to support covariant return types alongside this. That way, we can have generics in a class hierarchy where fluent methods can return the correct types.
For example, consider an example in Java where we want to define a custom list type with a generic type T (MyList<T> in the example). There may well be things that we want to do differently when we know that we have a list of SObjects (for example, have a method to do a database update).
In the example below, the fluent method, add(), returns "this". SObjectList can override add() to return itself rather than a MyList, keeping the right context as we call add() a number of times.
That pattern is not currently possible in Apex because it does not support covariant return types (https://ideas.salesforce.com/s/idea/a0B8W00000GdXOCUA3/support-covariant-return-types-in-apex).
public class Main {
public static void main(String[] args) {
MyList<Integer> intList = new MyList<Integer>()
.add(3)
.add(5);
System.out.println("ints: " + intList.toString());
SObjectList<Account> accountList = new SObjectList<Account>()
.add(new Account("Foo"))
.add(new Account("Bar"))
.doUpdate();
System.out.println("SObjects: " + accountList.toString());
}
static class SObject {
@Override
public String toString() {
return "Hi, I'm an SObject";
}
}
static class Account extends SObject {
private final String name;
public Account(String name) {
this.name = name;
}
@Override
public String toString() {
return "Account Name: " + name;
}
}
static class MyList<T> {
private final List<T> theList;
public MyList() {
theList = new ArrayList<T>();
}
public MyList<T> add(T toAdd) {
theList.add(toAdd);
return this;
}
public String toString() {
return theList.stream().map(Objects::toString).collect(Collectors.joining(", "));
}
}
static class SObjectList<T extends SObject> extends MyList<T> {
public SObjectList() {
super();
}
@Override
public SObjectList<T> add(T toAdd) {
super.add(toAdd);
return this;
}
public SObjectList<T> doUpdate() {
System.out.println("Do a database update!");
return this;
}
}
}