Value Preservation and Polysemy -> context dependent integer literals

Fawzi Mohamed fmohamed at mac.com
Fri Dec 5 03:20:24 PST 2008


On 2008-12-05 09:40:03 +0100, Don <nospam at nospam.com> said:

> Andrei Alexandrescu wrote:
>> Sergey Gromov wrote:
>>> Thu, 04 Dec 2008 09:54:32 -0800, Andrei Alexandrescu wrote:
>>> 
>>>> Fawzi Mohamed wrote:
>>>>> On 2008-12-01 22:30:54 +0100, Walter Bright <newshound1 at digitalmars.com> said:
>>>>> 
>>>>>> Fawzi Mohamed wrote:
>>>>>>> On 2008-12-01 21:16:58 +0100, Walter Bright <newshound1 at digitalmars.com> said:
>>>>>>> 
>>>>>>>> Andrei Alexandrescu wrote:
>>>>>>>>> I'm very excited about polysemy. It's entirely original to D,
>>>>>>>> I accused Andrei of making up the word 'polysemy', but it turns out it 
>>>>>>>> is a real word! <g>
>>>>>>> Is this the beginning of discriminating overloads also based on the 
>>>>>>> return values?
>>>>>> No. I think return type overloading looks good in trivial cases, but as 
>>>>>> things get more complex it gets inscrutable.
>>>>> I agreee that return type overloading can go very bad, but a little bit 
>>>>> can be very nice.
>>>>> 
>>>>> Polysemy make more expressions typecheck, but I am not sure that I want that.
>>>>> For example with size_t & co I would amost always want a stronger 
>>>>> typechecking, as if size_t would be a typedef, but with the usual rules 
>>>>> wrt to ptr_diff, size_t,... (i.e. not cast between them).
>>>>> This because mixing size_t with int, or long is almost always 
>>>>> suspicious, but you might see it only on the other platform (32/64 
>>>>> bit), and not on you own.
>>>>> 
>>>>> Something that I would find nice on the other hand is to have a kind of 
>>>>> integer literals that automatically cast to the type that makes more 
>>>>> sense.
>>>> Wouldn't value range propagation take care of that (and actually more)? 
>>>> A literal such as 5 will have a support range [5, 5] which provides 
>>>> enough information to compute the best type down the road.
>>> 
>>> It sounds very nice and right, except it's incompatible with Cee.
>>> 
>>> Well, you can safely reduce bit count so that assigning "1025 & 15" to
>>> "byte" would go without both a cast and a warning/error.  But you cannot
>>> grow bitcount beyond the C limits, that is, you cannot return long for
>>> "1024 << 30."  You should probably report an error, and you should
>>> provide some way to tell the compiler, "i mean it."
>>> 
>>> In the worst case, any shift, multiplication or addition will result in
>>> a compiler error.  Do I miss something?
>> 
>> Well any integral value carries:
>> 
>> a) type as per the C rule
>> 
>> b) minimum value possible
>> 
>> c) maximum value possible
>> 
>> The type stays the type as per the C rule, so there's no change there. 
>> If (and only if) a *narrower* type is asked as a conversion target for 
>> the value, the range is consulted. If the range is too large, the 
>> conversion fails.
>> 
>> Andrei
> 
> Any idea how hard this would be to implement?
> 
> Also we've got an interesting case in D that other languages don't 
> have: CTFE functions.
> I presume that range propagation would not apply during evaluation of 
> the CTFE function, but when evaluation is complete, it would then 
> become a known literal, which can have precise range propagation. But 
> there's still some funny issues:
> 
> uint foo(int x) { return 5; }
> 
> int bar(int y)
> {
>      ubyte w = foo(7); // this is a narrowing conversion, generates 
> compiler warning (foo is not called as CTFE).
>      return 6;
> }
> 
> enum ubyte z = foo(7); // this is range propagated, so narrowing is OK.
> enum int q = bar(3); // still gets a warning, because bar() didn't compile.
> 
> int gar(T)(int y)
> {
>      ubyte w = foo(7);
>      return 6;
> }
> 
> enum int v = gar!(int)(3); // is this OK???

What I would like is that one type of integer literals (optimally the 
one without annotation) has *no* fixed C type, but is effectively 
treated as an arbitrary dimension integer.
Conversion form this arbitrary precision integer to any other type are 
implicit as long as the *value* can be represented in the end type, 
otherwise they fail.

ubyte ub=4; // ok
byte ib=4; // ok
ubyte ub=-4; // failure
ubyte ub=cast(ubyte)cast(byte)-4; // ok (one could see if the removal 
of cast(byte) should be accepted
byte ib=-4; // ok
byte ib=130; // failure
float f=1234567890; // ok even if there could be precision loss
int i=123455; // ok
long i= 2147483647*2; // ok

note that as the value is known at compile time this can always be 
checked, and one would get rid of annotations  most of the time L UL 
s...
Annotations should stay for compatibility with C and a short way 
instead of for example cast(uint)1234 .

This thing has one problem, and that is overloaded function calls... in 
that case a rule has to be chosen:  find the smallest signed and 
unsigned type that can represent the number. If both are ok, fail, 
otherwise choose the one that is ok, could be a possible rule, anyway 
that should be discussed to make the compiler work reasonable.

So this is what I would like, I do not know how this matches with the 
polysemy proposal, because from  Andrei comments I am not sure I have 
understood it correctly.

So to answer Don within my proposal your code would not be correct because

>      ubyte w = foo(7);

needs a cast, even when performed at compile time. You have no new 
types, special rules only apply to integer literals, as soon as the 
assume a fixed C type, then the normal rules are valid.






More information about the Digitalmars-d mailing list