Eric Gunnerson said:
We'll have some new information on the constraints syntax - and the other
language features - on the MSDN C# developer center in the next few weeks.
This seems to indicate that the generics extension to C# and the .Net
framework is not yet cast into stone. Good! From all information on C#
generics I have seen so far it seems to lack essential features for
effective generic programming, most notable the ability to infer associated
types from type arguments.
Essentially, I'm strongly interested in implementing algorithms independent
from the underlying data structure. This is essentially the core of C++'s
STL: algorithms are not bound to a particular data structure but instead
operate on auxiliary entities which form an abstraction of the algorithm's
needs. For example, the STL algorithms operate on iterators.
To be more concrete, say I want to implement a simple algorithm determining
the position of the minimum value in a multi-pass sequence. A C++ algorithm
for this would look something like this:
template <typename ForwardIterator>
ForwardIterator
min_element(ForwardIterator begin, ForwardIterator end)
{
ForwardIterator rc = begin;
if (begin != end)
while (++begin != end)
if (*begin < *rc)
rc = begin;
return rc;
}
Now, the C# approach to some aspects of this function is somewhat different
but essentially the same functionality could be reasonable, too. Instead of
using an iterator, probably an enumerator would be used and the less than
operator would be replaced by call to 'comareTo()' of an comparer interface:
public interface Enumerator<T> {
public T next();
// probably some more functions
}
public interface Comparer<T> {
public bool compareTo(T other);
}
public class algos {
public static E MinElement<E, C>(E enumerator, C comparer)
where E: Enumerator<T> // or: E: Enumerator<E.ValueType>
where C: Comparer<T> // ... C: Comparer<E.ValueType>
{
// whatever...
}
}
The tricky part is the [reasonable] need to specify the details of the
type arguments in the constraints: although the sequence' element type 'T'
is implicit in 'E' and 'C', it has to be accessible in the constraints,
too - well, that is, in the form given above, it is actually infered rather
than given. Of course, there are other alternatives like allowing class
level aliases as is indicated by the comments but being able to infer
associated types via the constraints seems more consistent.
I also considered using the corresponding interfaces directly, ie.
something like this:
...
public static Enumerator<T> MinElement<T>(Enumerator<T> enumerator,
Comparer<T> comparer)
...
but this doesn't really scale: for algorithms a little bit more complex
there are typically multiple types associated with just a singleargument
to the function. While it is reasonable for these arguments to support
multiple interfaces, it doesn't seem feasible to fold all those types
into just one interface. Also, the argument types would tend to be rather
specific to a particular algorithm which is clearly not the goal. The
requirements imposed by the constraints to implement certain interfaces is
already bad enough with fairly general interfaces.
This is clearly the most important feature which seems to be absent (at
least from the public documentation I have seen; I can't install Gyro
and check there because I'm a professional software developer and not a
researcher while the license effectively seems to exclude the former).
The other feature I would like to see although I think it is possible to
emulate it to some degree is [partial] specialization: Given a generic
algorithm, provide a specialized implementation for a more specific case.
For functions this can be mostly implemented using overloading possibly
combined with some form of tagging scheme. However, spezializing the
generic implementation makes the intent clearer and there is no good
alternative approach for generic classes (maybe it is doable using some
form of delegation together with corresponding overloading but this does
not seem to be particularily maintainable.