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

Reply via email to