I had postponed any decision on Freya indexers until I could find a better model for representing name overloading in the symbol table. The original data structure was borrowed from Blue, and it was based in a clever trick: each context table contained a "group symbol" entry, which associated a name like WriteLine to the list of overloaded methods. At the same time, each of these methods was included independently. Since the context table is a kind of hash dictionary, method names were "decorated" or mangled, adding information from the parameter types.
I started with a version of Blue without indexers, and that's the reason why the symbol table only considered overloading for methods, but not for properties. There was another problem with explicit and implicit user defined conversions. The raw op_Implicit and op_Explicit methods violate one important rule in Freya and C#: they cannot be distinguished by the parameters signature! Suppose you write this in C#:
public static operator explicit double(Complex);
public static operator explicit float(Complex);
They translate to something like this:
public static double op_Explicit(Complex);
public static float op_Explicit(Complex);
Both methods have identical parameter lists, and they only differ in their return types. Of course, this is forbidden in C# and Freya... but is supported by the CLR. But the decorated parameter trick was inappropiate for representing this situation.
I have solved the problem by only including the group name for user defined conversions and indexers. Probably, there's no reason for including decorated method names in the hash table, but I won't mess right now with such a far reaching change in the compiler.
Finally, Freya has full functional indexers, following Visual Basic.NET. The reason:
- The VB model is the most general.
- Surprisingly, you can access secondary indexers from a C# application.
- So far, I haven't discovered any important drawback in the VB model.
I have also added lifted operators to Freya: these are automatic extensions for predefined and user operators for dealing with nullable types, and they imitate the behavior of SQL operators when they act on null values.