+ Start a Discussion

Java-like generic programming in Apex?

Before I ran off and created an IdeaExchange post I thought I'd run an idea past the great minds here and make sure I'm not overlooking obvious work-arounds!


I'd really like to create some reusable extensions to Apex functionality, such as a multimap implementation, where the same code could work with arbitrary objects while maintaining good type safety for each specific instance.


With Java-style generics, I could, for example, declare a class like:


public with sharing class MultiMap<K,V> { foo... }


The "<K,V>" would be the variable types used for the multimap's key and value data, perhaps implemented as Map<K,Integer> and List<List<V>>, respectively (map ties keys to the index of the outer list).


Instantiating a multimap would be as easy as:


MultiMap<String,Contact> myVar = new MultiMap<String,Contact>{};

Because that instance uses concrete object types (String and Contact), all data passed to or returned from the multimap would be automatically checked (and cast, if appropriate).
The only alternative I can see would be defining something like:
public with sharing class MultiMap {
  private Schema.SObjectType keyType { get; set; }
  private Schema.SObjectType valueType { get; set; }
  MultiMap(Schema.SObjectType K, Schema.SObjectType V) {keyType = K; valueType = V;}
... and then instantiating it like:
MultiMap myVar = new MultiMap( String.sObjectType, Contact.sObjectType );
If anyone can think of a way to do something like this in a type-safe manner without resorting to a ton of assertions, I'd love to hear it.
If not (and assuming the consensus reply is not "Andy, you are an idiot"), I'll file this in IdeaExchange.

There are template classes in Apex Code, but you can't currently extend these or make your own. For example, you can do Set<String> or Map<String,Account>. If you attempt to write a class using accesstype class classname<param>, you'll get a "type parameters not supported" error, which suggests that they are aware of this limitation and might do something with it in some future release. However, to make a custom class right now, you would be able to use the Object class, which represents any generic type of entity. However, since Apex is non-reflective (as opposed to Java, C++, Perl, PHP, Ruby, JavaScript, and every other modern OO language), you couldn't strictly enforce type checks at runtime or even compile-time. The sole exception to this appears to be sObjects, which does support a limited type of reflection by way of the generic Sobject member functions; you can create a class that could dynamically choose which type of sObject to hold or reject based on private members. Normally this is in relation to the Database member functions to insert, update, delete, or query objects that are not known until runtime. I have wanted this sort of functionality for a while, because I end up having to reinvent the wheel each time I need a standard piece of functionality, such as a custom-sortable list class. If you posted this idea to the IdeaExchange, you'd certainly have my vote.


Is there any reflection like thing in Apex?

Suppose we got a list of all methods available in  a custom class, using Schema.

So that , we can also invoke that method found as name in above list.


Apex Code is currently defined as "strongly typed", and so does not lend itself to reflection. They would have to relax their constraints and introduce runtime constraint checking to allow the possibility of reflection. Currently, if the Force.com compiler detects that the function you're attempting to call may or may not exist, you receive a compile-time error. The only "Dynamic" bit they have is Sobject.get(), the purpose of which is to allow you to specify a field that is determined at runtime.


Consider the contrived following example:



class A {
  public string x1() { return 'hello'; }

class B extends class A {
  public string x2() { return x1() + ' world'; }

A a1 = new B();
A a2 = new A();

System.debug(a1.x1()); // Okay
System.debug(a1.x2()); // Compiler says NOT okay, even though a1 is a B.
System.debug( ((B)a1).x2() ); // Okay, cast into B.
System.debug( a2.x1()); // Okay
System.debug( a2.x2()); // NOT okay
System.debug( ((B)a2).x2() ); // Runtime says NOT okay, a2 is not a B.

As you can see, the compiler makes every effort to determine if a call could possibly fail at compile time. Casting is the only mechanism that allows some dynamic runtime freedom, but the result ends up in more try/catch statements to make sure nothing bad happens, as opposed to true reflection, where you could determine if calling the function would cause something bad. Reflection allows code to be reactive, adjusting to changes in itself, while compiler type checking is proactive, forcing all of the code to be verified as soon as possible.



This idea isn't just a good one, it's an imperative to code reduction, code reuse, and good programming in-general.


The last couple days I've noticed our project makes regular use of a labeled list.  Due to the lack of a common base class in Apex for custom objects, we created our own, I'll call it CustomObject for this example.



public virtual class LabeledCustomObjectList {
public LabeledCustomObjectList (String aLabel){
label = aLabel;

public void add(CustomObject anItem){ itemList.add(anItem); }

public String label { get; private set; }

protected List<CustomObject> itemList = new List<CustomObject>();

public virtual List<CustomObject> getItemList(){ return itemList; }



Our VisualForce pages make regular use of iterating through a list of labels, like categories of lists, then iterating through the list that goes with it inside a table cell.


Unfortunatley, up and down-casting might work with each item in the list, but the type of itemList can not be casted as a whole to List<CustomObjectSubclass> without compile or runtime errors.


O, the joys of static-type checking!


As a result, we end-up with multiple classes different from the proposed base class in only the types of members in itemList.  


So much for code re-use or the promise of object-oriented programming.  Alas, if I could only use Smalltalk on Salesforce instead of Apex.


Anyway, as Salesforce's Apex is so inspired by Java (too bad it couldn't find inspiration elsewhere), implementing Java's custom generics might be a step in the right direction.  Or perhaps, allowing Ruby in addition to Apex on Salesforce might be another approach.


Or short of that, providing a macro pre-processor that would allow us to define a class using macros as in:


#define LabeledLlistClass(classname, itemType) {
public class classname {
public string (String aLabel) { label = aLabel; }
public void add(itemType anItem) { temList.add(anItem); }

public String label { get; private set; }

protected List<itemType> itemList = new List<itemType>();

public virtual List<itemType> getItemList() { return itemList; }



At least with a pre-processor, Salesforce wouldn't have to make the Apex language any more useful internally, but they could make it more flexible for programmers to minimally create the illusion of code reuse.  At least programmers could create common implemetnations of local idioms that would improve their code's consistency and readability.

Frank N.Frank N.

Hi, sorry for bumping this post but we are currently in need of being able to parameterize our classes, for example a custom map that both immediately sorts on key as well as being able to repeat on it's values instead of it's keys:


global class SortedMapIterator<K, V> implements Iterator<sObject> { }


However, parameterized classes are still not allowed. Whats the word from Salesforce on this? Will this functionality ever be included? Or is there another way of solving this?