[Grace-core] Typing of Number

Andrew P. Black black at cs.pdx.edu
Mon Jun 20 10:51:21 PDT 2011


On 20 Jun 2011, at 2:53, James Noble wrote:

> You'd be better of double-dispatching:
> 
> class Rational {
>   method +(other : Number) -> Rational {
>     other.addRational(self)
>   }
> }

Exactly.  Michael, your other.asRational must fail if the argument is inexact, because an inexact number has no rational representation.

Also, Michael's lament:

> with the "once inexact,
> always inexact" behaviour you'd [often] end up with "everything inexact",
> since you could never tell if you'd introduced an inexact type
> somewhere along the line (perhaps from an argument). 


This sounds a bit like wishing that π were 3.  That _would_ make everything simpler ... but it just ain't so.


> 
> or, alternatively, using a big typecase:
> 
> class Rational {
>   method +(other : Number) -> Rational {
>       match(other) {
>          case {Rational r -> self.addRational(r) }
>          case {Machine.Integer64 m -> self.addInteger64(m) }
>       // no else case, did we say that would raise a horrible error?
>       }
>   }
> }

The double-dispatch will behave like a distributed typecase.  If we want to actually honor our intention to allow library builders to add new representations of numbers, then we better use double-dispatch rather than a big typecase in every operation.

> 
>> It isn't the static typing that determines the return type, but the
>> dynamic type of the receiver, just like any other method.
> 
> Good... 
> 
>> It would
>> work the same way without the types (and it does make 2*(2+i) == 4,
>> assuming an implementation of Complex.asRational).

There is no representation of a complex number as a Rational.  So complex.asRational must fail if the imaginary part is non-zero.  No amount of type mumbo-jumbo can ever justify arithmetic giving me the wrong answer.

2+1.i  must EITHER give us a complex number, or fail.  It can NEVER give us 2 — unless we want the language to be an example of what is wrong with computer science.

> which is why we need to think about "no implicit conversions..."
> (I'm not sure whether Go really does this, but it says
> "Go does not support implicit type conversion. 
> Operations that mix different types require casts (called conversions in Go).")
> 
> I can't see why we'd do more implicitly than Go does.

I can't see what rule we might use to trigger implicit type conversions.  Are you going to suggest one,or are we sticking to our guns for now?


> PS: Go's identifier rules - Rob Pike probably knows as much about unicode programing languages as anyone.
> 
> It was important to us to extend the space of identifiers from the confines of ASCII. Go's rule—identifier characters must be letters or digits as defined by Unicode—is simple to understand and to implement but has restrictions. Combining characters are excluded by design, for instance. Until there is an agreed external definition of what an identifier might be, plus a definition of canonicalization of identifiers that guarantees no ambiguity, it seemed better to keep combining characters out of the mix. Thus we have a simple rule that can be expanded later without breaking programs, one that avoids bugs that would surely arise from a rule that admits ambiguous identifiers.


This seems like a reasonable rule — although we would allow APOSTROPHE (Unicode 0027) in addition to class    It would exclude the tricky cases with combining character about which Michael was fretting.  I'm not actually sure that a Unicode NUMBER is; does it include, for example, TAMIL NUMBER TEN (Unicode 0BF0)?

	Andrew


More information about the Grace-core mailing list