July 07, 2009
Walter Bright wrote:
> Something for everyone here.
> 
> 
> http://www.digitalmars.com/d/1.0/changelog.html
> http://ftp.digitalmars.com/dmd.1.046.zip
> 
> 
> http://www.digitalmars.com/d/2.0/changelog.html
> http://ftp.digitalmars.com/dmd.2.031.zip

Why is 'final switch' required? Another possible way of dealing with the same issue would be:

switch(e) {
case E.A: blah; break;
case E.B: blah; break;
...
default: assert(0);
}

Ie, if switch is over an enum type, and the 'default' clause consists only of assert(0), the compiler could generate a warning if some of the possible enum values never appear in a case statement.

It's not quite the same as 'final switch', but I think it captures most of the use cases.
July 07, 2009
KennyTM~ Wrote:
> Maybe http://msdn.microsoft.com/en-us/vcsharp/aa336815.aspx .

That compromise design looks good to be adopted by D too :-)

Bye,
bearophile
July 07, 2009
On Tue, Jul 7, 2009 at 11:15 AM, Jarrett Billingsley<jarrett.billingsley@gmail.com> wrote:
> On Tue, Jul 7, 2009 at 1:48 AM, Andrei Alexandrescu<SeeWebsiteForEmail@erdani.org> wrote:
>>
>> Walter has implemented an ingenious scheme for disallowing narrowing conversions while at the same time minimizing the number of casts required. He hasn't explained it, so I'll sketch an explanation here.
>>
>> The basic approach is "value range propagation": each expression is associated with a minimum possible value and a maximum possible value. As complex expressions are assembled out of simpler expressions, the ranges are computed and propagated.
>>
>> For example, this code compiles:
>>
>> int x = whatever();
>> bool y = x & 1;
>>
>> The compiler figures that the range of x is int.min to int.max, the range of 1 is 1 to 1, and (here's the interesting part), the range of x & 1 is 0 to 1. So it lets the code go through. However, it won't allow this:
>>
>> int x = whatever();
>> bool y = x & 2;
>>
>> because x & 2 has range between 0 and 2, which won't fit in a bool.
>
> Very cool.  :)
>
>> The approach generalizes to arbitrary complex expressions. Now here's the trick though: the value range propagation is local, i.e. all ranges are forgotten beyond one expression. So as soon as you move on to the next statement, the ranges have been forgotten.
>>
>> Why? Simply put, increased implementation difficulties and increased compiler memory footprint for diminishing returns. Both Walter and I noticed that expression-level value range propagation gets rid of all dangerous cases and the vast majority of required casts. Indeed, his test suite, Phobos, and my own codebase required surprisingly few changes with the new scheme. Moreover, we both discovered bugs due to the new feature, so we're happy with the status quo.
>
> Sounds fairly reasonable.
>
>> Now consider your code:
>>
>> byte x,y,z;
>> z = x+y;
>>
>> The first line initializes all values to zero. In an intra-procedural value range propagation, these zeros would be propagated to the next statement, which would range-check. However, in the current approach, the ranges of x, y, and z are forgotten at the first semicolon. Then, x+y has range -byte.min-byte.min up to byte.max+byte.max as far as the type checker knows. That would fit in a short (and by the way I just found a bug with that occasion) but not in a byte.
>
> The only thing is: why doesn't _this_ fail, then?
>
> int x, y, z;
> z = x + y;
>
> I'm sure it's out of convenience, but what about in ten, fifteen years when 32-bit architectures are a historical relic and there's still this hole in the type system?
>
> The same argument applies for the implicit conversions between int and uint.  If you're going to do that, why not have implicit conversions between long and ulong on 64-bit platforms?
>

I think I've confused the mailing list's threading algorithm.
July 07, 2009
Daniel Keep, el  7 de julio a las 15:40 me escribiste:
> 
> 
> Andrei Alexandrescu wrote:
> > bearophile wrote:
> >> Jason House:
> >>> Hardly. There seemed to mostly be complaints about it with Andrei saying things like "I can't believe you don't see the elegance of the syntax". In the end, Andrei commented that he shouldn't involve the community in such small changes and went silent.<
> >>
> >> He was wrong. Even very intelligent people now and then do the wrong thing.
> > 
> > Of course the latter statement is true, but is in no way evidence supporting the former. About the former, in that particular case I was right.
> > 
> > Andrei
> 
> Now, now.  Let's all play nicely together...
> 
> I don't like the `case a:..case b:` syntax.  It doesn't matter.  The functionality is in place and the syntax has a sane explanation and rationale.
> 
> Unless there's some egregious problem aside from being a bit on the ugly side [1], it's just bike-shedding.  And I'm so, SOOO sick of bike-shedding.

I think Walter is right, this syntax introduce an inconsistency in the ".." operator semantics, which is used with inclusive meaning sometimes (case) and with exclusive meaning other times (slices and foreach).

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
July 07, 2009
On Tue, Jul 7, 2009 at 1:48 AM, Andrei Alexandrescu<SeeWebsiteForEmail@erdani.org> wrote:
>
> Walter has implemented an ingenious scheme for disallowing narrowing conversions while at the same time minimizing the number of casts required. He hasn't explained it, so I'll sketch an explanation here.
>
> The basic approach is "value range propagation": each expression is associated with a minimum possible value and a maximum possible value. As complex expressions are assembled out of simpler expressions, the ranges are computed and propagated.
>
> For example, this code compiles:
>
> int x = whatever();
> bool y = x & 1;
>
> The compiler figures that the range of x is int.min to int.max, the range of 1 is 1 to 1, and (here's the interesting part), the range of x & 1 is 0 to 1. So it lets the code go through. However, it won't allow this:
>
> int x = whatever();
> bool y = x & 2;
>
> because x & 2 has range between 0 and 2, which won't fit in a bool.

Very cool.  :)

> The approach generalizes to arbitrary complex expressions. Now here's the trick though: the value range propagation is local, i.e. all ranges are forgotten beyond one expression. So as soon as you move on to the next statement, the ranges have been forgotten.
>
> Why? Simply put, increased implementation difficulties and increased compiler memory footprint for diminishing returns. Both Walter and I noticed that expression-level value range propagation gets rid of all dangerous cases and the vast majority of required casts. Indeed, his test suite, Phobos, and my own codebase required surprisingly few changes with the new scheme. Moreover, we both discovered bugs due to the new feature, so we're happy with the status quo.

Sounds fairly reasonable.

> Now consider your code:
>
> byte x,y,z;
> z = x+y;
>
> The first line initializes all values to zero. In an intra-procedural value range propagation, these zeros would be propagated to the next statement, which would range-check. However, in the current approach, the ranges of x, y, and z are forgotten at the first semicolon. Then, x+y has range -byte.min-byte.min up to byte.max+byte.max as far as the type checker knows. That would fit in a short (and by the way I just found a bug with that occasion) but not in a byte.

The only thing is: why doesn't _this_ fail, then?

int x, y, z;
z = x + y;

I'm sure it's out of convenience, but what about in ten, fifteen years when 32-bit architectures are a historical relic and there's still this hole in the type system?

The same argument applies for the implicit conversions between int and uint.  If you're going to do that, why not have implicit conversions between long and ulong on 64-bit platforms?
July 07, 2009
aarti_pl, el  7 de julio a las 00:27 me escribiste:
> Leandro Lucarella pisze:
> >Andrei Alexandrescu, el  6 de julio a las 10:44 me escribiste:
> >>>>And what did those people use when they wanted to express a range of case labels? In other words, where did those people turn their heads towards?
> >>>They probably used an if.
> >>So they used an inferior means to start with.
> >Yes, but when you try to make people move to a different language, you
> >have to do considerably better. When I have to choose between something
> >well know, well supported and mature and something that is, at least,
> >unknown (even if it's mature and well supported, I won't know that until
> >I use it a lot so is a risk), I want to be really good, not just barely
> >good.
> >Details as this one are not deal breaker on their own, but when they are
> >a lot, it tends to make the language look ugly as a whole.
> >What bugs me the most is there are a lot of new constructs in the language
> >that are plain ugly, from the start. D is buying it's own baggage
> >(__traits, enum for manifest constants, now the case range, and I'm sure
> >I'm forgetting something else) with no reason...
> 
> ...
> * foreach_reverse
> * access to variadic function parameters with _argptr & _arguments
> * mess with compile time is expression (sorry, that's my favorite ugliness :-] )

But these ones at least are not new (I'm sure they were new at some point, but now are baggage). The new constructs are future baggage.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
July 07, 2009
Andrei Alexandrescu, el  6 de julio a las 18:32 me escribiste:
> Leandro Lucarella wrote:
> >Andrei Alexandrescu, el  6 de julio a las 10:44 me escribiste:
> >>>>And what did those people use when they wanted to express a range of case labels? In other words, where did those people turn their heads towards?
> >>>They probably used an if.
> >>So they used an inferior means to start with.
> >Yes, but when you try to make people move to a different language, you have to do considerably better. When I have to choose between something well know, well supported and mature and something that is, at least, unknown (even if it's mature and well supported, I won't know that until I use it a lot so is a risk), I want to be really good, not just barely good.
> 
> That goes without saying.
> 
> >Details as this one are not deal breaker on their own, but when they are a lot, it tends to make the language look ugly as a whole.
> 
> You are just saying it's ugly. I don't think it's ugly. Walter doesn't think it's ugly. Other people don't think it's ugly. Many of the people who said it's ugly actually came up with proposals that are arguably ugly, hopelessly confusing, or both. Look at only some of the rehashed proposals of today: the genial "case [0 .. 10]:" which is horribly inconsistent, and the awesome "case 0: ... case 10:", also inconsistent (and gratuitously so) because ellipses today only end lists without having something to their right. The authors claim those are better than the current syntax, and one even claimed "beauty", completely ignoring the utter lack of consistency with the rest of the language. I don't claim expertise in language design, so I wish there were a few good experts in this group.

Please read the thread at D NG, the current syntax *is* inconsistent too.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
July 07, 2009
Hello Daniel,

> BCS wrote:
> 
>> Hello Daniel,
>> 
>>> [1] like me. My girlfriend disagrees with me on this,
>>> 
>> You have a girlfriend that even bothers to have an opinion on a
>> programming issue, lucky bastard.
>> 
> No, when I said "like me", I meant:
> 
> "Unless there's some egregious problem aside from being a bit on the
> ugly side (like me), ..."
> 
> My girlfriend is actually a nurse, but I could ask for her opinion on
> case ranges if you want.  :)
> 

Odd, the exact same words read differently around midnight. :b


July 07, 2009
On Tue, 07 Jul 2009 03:33:24 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> Robert Jacques wrote:
>>  That's really cool. But I don't think that's actually happening (Or are these the bugs you're talking about?):
>>      byte x,y;
>>     short z;
>>     z = x+y;  // Error: cannot implicitly convert expression (cast(int)x + cast(int)y) of type int to short
>>      // Repeat for ubyte, bool, char, wchar and *, -, /
>
> http://d.puremagic.com/issues/show_bug.cgi?id=3147 You may want to add to it.

Added. In summary, + * - / % >> >>> don't work for types 8-bits and under. << is inconsistent (x<<1 errors, but x<<y compiles). All the op assigns (+= *= -= /= %= >>= <<= >>>=) and pre/post increments (++ --) compile which is maddeningly inconsistent, particularly when the spec defines ++x as sugar for x = x + 1, which doesn't compile.

>> And by that logic shouldn't the following happen?
>>      int x,y;
>>     int z;
>>     z = x+y;  // Error: cannot implicitly convert expression (cast(long)x + cast(long)y) of type long to int
>
> No. Int remains "special", i.e. arithmetic operations on it don't automatically grow to become long.
>
>> i.e. why the massive inconsistency between byte/short and int/long? (This is particularly a pain for generic i.e. templated code)
>
> I don't find it a pain. It's a practical decision.

Andrei, I have a short vector template (think vec!(byte,3), etc) where I've had to wrap the majority lines of code in cast(T)( ... ), because I support bytes and shorts. I find that both a kludge and a pain.

>> BTW: this means byte and short are not closed under arithmetic operations, which drastically limit their usefulness.
>
> I think they shouldn't be closed because they overflow for relatively small values.

Andrei, consider anyone who want to do image manipulation (or computer vision, video, etc). Since images are one of the few areas that use bytes extensively, and have to map back into themselves, they are basically sorry out of luck.


July 07, 2009
Jarrett Billingsley wrote:
> The only thing is: why doesn't _this_ fail, then?
> 
> int x, y, z;
> z = x + y;
> 
> I'm sure it's out of convenience, but what about in ten, fifteen years
> when 32-bit architectures are a historical relic and there's still
> this hole in the type system?

Well 32-bit architectures may be a historical relic but I don't think 32-bit integers are. And I think it would be too disruptive a change to promote results of arithmetic operation between integers to long.

> The same argument applies for the implicit conversions between int and
> uint.  If you're going to do that, why not have implicit conversions
> between long and ulong on 64-bit platforms?

This is a different beast. We simply couldn't devise a satisfactory scheme within the constraints we have. No simple solution we could think of has worked, nor have a number of sophisticated solutions. Ideas would be welcome, though I need to warn you that the devil is in the details so the ideas must be fully baked; too many good sounding high-level ideas fail when analyzed in detail.


Andrei