[Grace-core] Typing of Number

Michael Homer mwh at ecs.vuw.ac.nz
Tue Jun 28 20:37:27 PDT 2011


On Tue, Jun 28, 2011 at 8:45 AM, James Noble <kjx at ecs.vuw.ac.nz> wrote:
>> The idea is that as well as self-type annotations and bounded type
>> variables there would be the possibility of referring to the
>> least-upper-bound type of two types,
>
> So I was looking at the website for Ceylon
>
> http://in.relation.to/Bloggers/IntroductionToCeylonPart10
>
> and it seems they have a way of doing this without self-types
> or LUB - but rather using annotations and union types.
> (e.g. an interface Castable<> which acts as an annotation
> describing to what types an object can be cast).
>
> How do you this approach compares?

There is essentially a self-type there: with the syntactic rewriting
from x * y to product(x, y), their Left type is the (static) type of
what would be the receiver in Grace. Result is limited to exactly one
or other of Left or Right, so it's the maximum of the two types,
rather than LUB. That does mean that something like Complex + Binary64
-> ComplexBinary64 isn't possible, but only one pair of their builtin
types hits that (Float * Whole).

The Castable interface basically defines the edges of a flat
pseudo-lattice. There's no transitivity in it, so all the possible
conversions are enumerated directly and conversion methods are defined
for each. Operations end up happening on the result type only, with
both operands converted to it first. As a result operators aren't
defined directly on objects, and instead a "times" or "plus" method is
called implicitly after the desugaring and conversion.

It looks like methods are overloaded on generics, so x.as<Result> will
invoke x.as<Float> or x.as<Whole> according to the type of Result, and
those have separate implementations. Since there's no shared supertype
of all numbers, or even any pair of them, the static types are always
exact. If there were, hypothetical dynamically-typed code could have
different behaviour than static code, since operands would be
converted to different types based on dynamic information. A Number
type causes problems too, since
left.as<Number>().times(right.as<Number>()) doesn't make any
improvement on where it started.

I like that as a way of declaring possible conversions and potentially
flagging some errors statically, but it seems like it still requires
self-types of some sort to work. Restricting the result to one or
other of the operand types cuts out a few possibilities, but maybe not
too many that matter. I don't think it can work on dynamically-typed
code without a semantic change though.
-Michael


More information about the Grace-core mailing list