[Grace-core] Typing of Number

Andrew P. Black black at cs.pdx.edu
Tue Jun 21 10:11:54 PDT 2011


On 21 Jun 2011, at 01:25 , James Noble wrote:

> Still there is the question: for things like arrays or collections, that do want 
> integral (actually a Natural, positive nonzero integer) index: 
> should the language require explicit conversions when 
> - a non-integral type is passed in (float, double, complex etc)

My suggestion would be that if an exact number is passed as an argument, and if the number is a valid index for the data structure, then the result is to extract the element.  Otherwise, it's an error.  

The normal case is that the index will come from an internal iterator.  The above rule will also work if the program does integer arithmetic, or uses indexes like floor(x/2), as one might do in a partition.    It wil liaise an error in other cases, which is the correct behavior, in my view.  

A more interesting question i: what should at()ifAbsent() do when the index is 2+3.i ?   The ifAbsentBlock, or an error?

> - when an integral but non Natural type is passed (byte, etc etc)

Eh?  Bytes aren't integers.

>> Do you mean "distinguished from each other" or "distinguished from non-numeric types"?
> 
> both I think: primarily distinguished from each other but this implies distinguished from non-numeric types.
> 
>> Binary64 and Binary128 have the same behavior as types.  And maybe that's exactly right: you want to be able to replace the Binary64 constructor methods by Binary128 constructors, and have the program continue to be type-correct, but with a more exact result. 
> 
> that only requies Binary128 is a subtype of Binary64. 

Yes, but it should also be possible to replace Binary128 by Binary62 and have the program continue to be type-correct, but with a less exact result.  That requires Binary64 is a subtype of Binary128.

Which raises the question: are our types a partial-order or a pre-order?

>> There is of course an efficiency argument for prohibiting re-implementation of integer: if you can tell from the type that a value has the particular built-in machine integer representation, you can emit machine instructions rather than method requests.  But it precludes the nice automatic conversion to BigNums that are so convenient.  Didn't we have some principles that covered this.
> 
> (looks it up)
> we've got:
> * The execution of the language should not depend on a program’s static types.
> * Efficiency is not a concern of this language design.
> * The language should support a simple performance model for simple programs. 
> 
> pragmatically we at least need to be able to link to C or Java libraries.

Does that mean that we need wrap-around 32-bit arithmetic as well, for compatibility with Java?  Argh!

> I think that it would be good e.g. to be able to say (and check statically) 
> that some computation is really in bytes,

Eh?  Bytes?  Bites?  Mad dogs and Englishmen?

> or machine integers (modulo 2^32 arithmetic :-), or floats
> and lives only within those types.    And I can see that - for those really restricted things -
> there should be no implicit conversions to types like Number or Rational. I think.
> This doesn't mean that literals can't be "contextual";
> nor does it mean that such types can't be a *subtype* of Number or Numeric or something, without _conversions_
> 
>>> I do think that if there's a
>>> Rational type it should be possible to constrain yourself to remaining
>>> within it somehow
> 
>> This sounds reasonable.  It also sounds reasonable to allow operations like addition of a complex number to a rational and taking the square-root of a rational, both of which will of course take you our of the rationals.
>> 
>> Is there a proposal for reconciling these two apparently reasonable, but conflicting, desires?
> 
> 
> I don't know.
> Even adding a complex to a rational is tricky: however it is implemented
> it means + on rational must accept either a rational OR a complex
> with different return types depending on the argument types...

No, it doesn't.  The obvious (to me) way to get these two conflicting behaviors is with two distinct operations: rational plus, which is constrained to keep one within the rationals, and numeric plus, which is constrained only to keep one within the numbers.

> I  fear we need to think about more actual examples. 
> Here's a nasty one:
> 
> say we have something like this:
> 
> a : unsignedByte  
> b : unsignedByte

Where does this idea that Bytes are some kind of Number come from?   Bytes are 8 bits of uninterpreted data.
> 
> a := 255
> b := 1 
> 
> print a + b    //  what should be printed?  Go I think would print 0? unsignedByte is basically arithmetic mod 256


The answer is clear if you take away the type declarations.

const a := 255
const b := 1

print a+b

I think (goes away to check) that the answer should be 256.

+ is an operation on Numbers, not on Bytes.   If we have byte objects, I would suggest that they understand operations like and() and nand() and or() and xor() but NOT +, because that would be confusing.   We could use ⊕ for addition mod 255, if you think that it's necessary, or just call it plusMod()

> 
>> Any of these variations can work.  I kind of like the last one, but the LOOJ-style system may be less jarring for people if we decide to have a SelfType.
> 
> OK yep, so one question is - does SelfType make sense if it is *not* exact? 

Yes.  Emerald had self-types (we invented them too) but no exact types.  Personally, I've never really seen the need for exact types; they are of the same ilk as final classes: a way of restricting the options of those who want to (re-)use your work.

	Andrew


	Andrew



More information about the Grace-core mailing list