On 24/03/2010 2:13 AM, Jonathan S. Shapiro wrote: > - Resolving an overloaded method call by consulting the available > definitions > in the current lexical context. > - Resolving a desired type class instance by consulting the > available instances > in the current lexical context. > - Resolving a template specialization (as in C++) by consulting the > available > specializations in the current lexical context. > > Each of these, fundamentally, is a matter of ad-hoc type-based > overload resolution. There seems to be no qualitative difference > between them, and no reason I can see to view any one as more tasteful > than any other.
The difference is that type classes are presented as a coherent stand-alone abstraction. The overloading permitted in other languages are all mixed in with other abstractions, overloads, namespaces and often conflicts with their subclassing/subtyping relations. > - A type class instance is a total or partial specialization of that > generic (not sure C# > supports this, so perhaps this should be taken in the style of C++ > partial template > specialization. Sure, C# supports something like it: interface IFoo<A,B> {} interface IBar<A> : IFoo<A, int> {} public static void Bar<F, B>(F foo) where F : IFoo<bool, B> { ... } > - Type class instance resolution is merely a variation on template > specialization selection. I'm not sure how "template specialization selection" works, but each instance in Haskell is global and unique. I like the idea of lexically scoped type classes, but it's not common. > It does not seem to me that there is any reason to restrict type > classes to virtual methods. For example, we might imagine defining a > hypothetical Eq type class as: > > type class Eq 'a { > // intentionally ignoring operator syntax issues here ... > instantiated equals :: 'a x 'a -> bool; > fn notEquals x y = ! equals x y; > } Type classes are restricted to virtual methods because type classes are intended purely as a specification of overloadable behaviour. If you want parametrically polymorphic behaviour, you can just write an ordinary notEquals function that depends on Eq 'a: notEquals :: Eq 'a => 'a -> 'a -> bool notEquals lhs rhs = !(equals lhs rhs) Functions and type classes permit extension in orthogonal directions, so mixing them seems counter-productive. > However, note that a type class instance is then a subclass (in the > sense that it inherits methods, virtual methods, and abstract virtual > method mandates) of its type class. There seems to be no inherent > reason to restrict the subclassing depth to one. > > Now if all of this is the case, then we must ask whether we shouldn't > just allow fields in [type] class definitions. I don't see any > particular *use* for fields in a type class, but at the same time I > see no need to exclude them arbitrarily. A Haskell data type can have instances for multiple type classes. If this is not permissible in your framework, then they're not type classes. If it is permissible, what do you do when two different type classes have the same field name? Seems like you run into multiple inheritance issues here. I'm not actually convinced the overhead of type classes is really a problem. A type class is an extreme abstraction mechanism, so employing it implies the abstraction is needed. I don't think most low level code needs much overloading, so worrying about type class overhead would be moot. However, assuming efficient overloading is needed, then why not introduce a single keyword, say "specialized", which can appear on either function or type class definitions: specialized class Eq 'a where eq :: 'a -> 'a -> bool specialized notEquals :: Eq 'a => 'a -> 'a -> bool By default, functions get dictionaries for smaller code size, and every function or type class annotated with "specialized" has its type class parameters fully specialized. I think this is a more orthogonal extension to achieve your performance goals without sacrificing abstraction. This also supports partial specializations, if only one type class of several passed to a function was specified as "specialized". Alternately, you can provide a different overload arrow syntax for specialized functions: notEquals :: Eq 'a ~> 'a -> 'a -> bool I'm not sure this really helps with CTS integration, but I'd hate to see BitC get saddled with an inferior semantics due to CTS. Scala gets away with it because the JVM uses full type erasure anyway, but it's a little more challenging on the CLR due to type-passing. I developed an encoding for type constructor polymorphism on the CLR which involves safe casts and separating dispatch from the representation [1]. The CLR's polymorphism is unfortunately crippled in some important ways. Sandro [1] http://higherlogics.blogspot.com/2009/10/abstracting-over-type-constructors.html _______________________________________________ bitc-dev mailing list bitc-dev@coyotos.org http://www.coyotos.org/mailman/listinfo/bitc-dev