June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Jonathan M Davis: >Well, I would pount out that you mentioning it more or less reopens the discussion,< You are right, but probably Walter will not sue me for reopening an old thread ;-) In the things you are saying you seem to ignore the "goto" I have written two times in my answers :-) >An extension of that is if you have two cases which are almost identical but where one of them needs to do something first before the code that is common between both cases.< You can write this C-style switch: switch (x) { case 0: foo(); case 1: bar(); } As this (this is D syntax that you can already use): void main() { int x, y; switch (x) { case 0: y++; goto case 1; case 1: y++; default: } } > A more complicated example would be one where you're doing something like Duff's Device: > > send(to, from, count) > register short *to, *from; > register count; > { > register n=(count+7)/8; > switch(count%8){ > case 0: do{ *to = *from++; > case 7: *to = *from++; > case 6: *to = *from++; > case 5: *to = *from++; > case 4: *to = *from++; > case 3: *to = *from++; > case 2: *to = *from++; > case 1: *to = *from++; > }while(--n>0); > } > } You can use gotos (this is a different function, it copies whole arrays, 'to' too is incremented): import std.stdio: writeln; void arrryCopy(short* to, short* from, int count) { foreach (_; 0 .. count / 8) { *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; } final switch (count % 8) { case 7: *to++ = *from++; goto case 6; case 6: *to++ = *from++; goto case 5; case 5: *to++ = *from++; goto case 4; case 4: *to++ = *from++; goto case 3; case 3: *to++ = *from++; goto case 2; case 2: *to++ = *from++; goto case 1; case 1: *to++ = *from++; break; case 0: break; } } void main() { short[9] a1 = 1; short[a1.length] a2; writeln(a1, " ", a2); arrryCopy(a2.ptr, a1.ptr, a1.length); writeln(a1, " ", a2); } I have used the static switch to avoid the default case. Using gotos like that is a bit less conventient than the C code, but I think it can be acceptable. > switch(value) > { > case 0: > do something... > case 1: > do something else... > case 2: > do a third thing... > case 3: > do yet more... > } You can translate it as: switch(value) { case 0: do something... goto case 1; case 1: do something else... goto case 2; case 2: do a third thing... goto case 3; case 3: do yet more... break; default: ... } Bye, bearophile | |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | > As this (this is D syntax that you can already use):
>
> void main() {
> int x, y;
> switch (x) {
> case 0: y++; goto case 1;
> case 1: y++;
> default:
> }
> }
Sorry, I meant something like:
void main() {
int x, y;
switch (x) {
case 0: y++; goto case 1;
case 1: y++; break;
default: break;
}
}
Bye,
bearophile
| |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Jonathan M Davis wrote:
> bearophile wrote:
>
>> 2) switch cases that don't end with goto or break:
>>
>> void main() {
>> int x, y;
>> switch (x) {
>> case 0: y++;
>> default: y--;
>> }
>> }
>
> I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements.
I agree. But the basic idea is to do extra work if you're doing something unusual, and falling through is unusual.
A while ago it was proposed to require each case block to end with a control flow transfer statement (break, continue, return, throw, or goto case XXX). The latter allows fall through in the rare cases that were needed, requiring just a bit of extra umph from the programmer. Perfect solution.
My recollection of the matter is that Walter rejected the proposal claiming that he uses fall through all the time. Don ran some measurements over Walter's own code and proved him copiously wrong. Walter had no retort to that argument, so he veered into a critique of the goto case XXX solution saying it's unmaintainable: when you moving code around you want to keep on falling through but with goto you'd need to update the goto target. However, it can be argued that logically you want to continue processing at some specific logical point, not to blindly fall through to whatever the heck code happens to be there.
So ultimately the whole thing fizzled. Apparently the current situation is optimal for programmers who use fall through "all the time", who move code that is fallen into all the time, have weird expectations of code after the move, and never check that jumps are made to the right labels.
As an aside, I think it's an interesting psychological phenomenon: I think we often have skewed beliefs about the frequency of our patterns. It often happens that switchers to a new language believe they won't be able to make it through the day without feature X (bitfields, anyone? :o)) yet practical experience soon shows otherwise.
Andrei
| |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | On Fri, 18 Jun 2010 17:03:24 -0400, Don <nospam@nospam.com> wrote:
> In the comments for bug 4077, "Bugs caused by bitwise operator precedence"
> it was asked why C gave & with lower precedence than ==, when it is unintuitive and a frequent source of bugs.
>
> I was quite shocked to find that the reason is backwards compatibility with the B programming language.
>
> Denis Ritchie says (http://cm.bell-labs.com/cm/cs/who/dmr/chist.html):
> --------------------
> At the suggestion of Alan Snyder, I introduced the && and || operators to make the mechanism [[short circuit evaluation]] more explicit.
>
> Their tardy introduction explains an infelicity of C's precedence rules. In B one writes
>
> if (a==b & c) ...
>
> to check whether a equals b and c is non-zero; in such a conditional expression it is better that & have lower precedence than ==. In converting from B to C, one wants to replace & by && in such a statement; to make the conversion less painful, we decided to keep the precedence of the & operator the same relative to ==, and merely split the precedence of && slightly from &. Today, it seems that it would have been preferable to move the relative precedences of & and
> ==, and thereby simplify a common C idiom: to test a masked value against another value, one must write
>
> if ((a&mask) == b) ...
>
> where the inner parentheses are required but easily forgotten.
> -----------------------------------
> Tragic. Can we end this madness?
>
> Could we give & | ^ the same precedence as ==, making
> (a & mask == b) an error, just as (a < b == c) is rejected?
> That way we could lay this common bug to rest. I've personally lost days of my life to this one. It's a bug 100% of the time.
>
> Or is too late to break backwards compatibility with B ?
>
> BTW I think this a great cautionary tale about the dangers of rating backwards compatibility too highly.
Well, you've got a big vote++ from this a & mask == b bug survivor. I also think your solution is simple and elegant.
| |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Fri, 18 Jun 2010 20:23:45 -0400, Jonathan M Davis <jmdavisProg@gmail.com> wrote:
> bearophile wrote:
>
>> Jonathan M Davis:
>>> but requiring that each case end with a break would seriously restrict
>>> the usefulness of switch statements.
>>
>> Time ago there was a long thread about this topic (and in the meantime
>> Walter has added the "static switch" that burns the fat chance to add to
>> D2 a second safer switch that fixes both the common kind of bugs caused by
>> C switch statements and not just the enum-switch bugs avoided by the
>> current static switch!) and I am not sure it's right to restart that
>> discussion again. Anyway, can you show me one example where requiring that
>> each case end with a break OR goto restricts the usefulness of switch
>> statements?
>>
>> Bye,
>> bearophile
>
> Well, I would pount out that you mentioning it more or less reopens the
> discussion, but in any case, the simplest answer would be if you have
> multiple values for the variable that your switching on which should all be
> using the same kind. Fortunately, D simplifies that by allowing you to put
> multiple values with a single case. An extension of that is if you have two
> cases which are almost identical but where one of them needs to do something
> first before the code that is common between both cases.
>
> A more complicated example would be one where you're doing something like
> Duff's Device:
>
> send(to, from, count)
> register short *to, *from;
> register count;
> {
> register n=(count+7)/8;
> switch(count%8){
> case 0: do{ *to = *from++;
> case 7: *to = *from++;
> case 6: *to = *from++;
> case 5: *to = *from++;
> case 4: *to = *from++;
> case 3: *to = *from++;
> case 2: *to = *from++;
> case 1: *to = *from++;
> }while(--n>0);
> }
> }
>
> Even if you drop the whole issue of the loop interleaving with the case
> statements in Duff's Device, you could still have a situation where you
> would have a series of things that should be done with how many of them you
> do depending on what the value you're switching on and you doing all of the
> preceding ones for each greater value. e.g.
>
> switch(value)
> {
> case 0:
> do something...
> case 1:
> do something else...
> case 2:
> do a third thing...
> case 3:
> do yet more...
> }
>
> If value were 0, you'd need to do everything that is done at each case
> statement, while if it were 2, you'd only need to do whatever is done for 2
> and 3.
>
> I grant you that in most cases, you don't need to do that sort of thing and
> that missing a break is an error, but there are definitely cases where being
> able to have case statements fall through can be quite handy. If it wouldn't
> likely break compatability with C/C++, I'd suggest requiring a continue if
> you wanted to fall through (since that wouldn't require a new keyword), but
> I think that that would break compatibility in cases where the switch is in
> a loop, so that's probably a no-go, and I very much doubt that Walter would
> want to add the keyword fallthrough or something similar.
>
> It is an issue, but it's a well-known one, and I don't think that requiring
> a break is worth the loss of power. If we push for a change, it should
> probably be in requiring a keyword to indicate that you meant to fall
> through. That would give you the safety without losing the power.
>
> - Jonathan M Davis
continue is a valid keyword inside a switch statement, so no, you can't use it.
| |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote:
> Jonathan M Davis:
>
>>Well, I would pount out that you mentioning it more or less reopens the discussion,<
>
> You are right, but probably Walter will not sue me for reopening an old thread ;-)
>
>
> In the things you are saying you seem to ignore the "goto" I have written two times in my answers :-)
>
I had forgotten about that use of goto. I do find it a bit ugly, but it works and makes it possible to require some sort of flow control statement at the end of a case block, thereby avoiding bugs where you forget a break.
I can't say that I'm enamoured at the idea of having to use goto for fallthrough, but I wouldn't be opposed to it. Part of the issue, I suppose, is that not only do I definitely use fallthrough at least some of the time, but I'm totally used to being aware of the issue and being appropriately careful about it. So, I don't see it as all that big a problem. However, it's enough of a problem for some people (and even those who are fully aware of it and pay attention do screw up from time to time) that it could very well merit requiring a goto for fallthrough.
- Jonathan M Davis
| |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sat, 19 Jun 2010 05:22:47 +0300, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: > Walter had no retort to that argument, so he veered into a critique of the goto case XXX solution saying it's unmaintainable: when you moving code around you want to keep on falling through but with goto you'd need to update the goto target. However, it can be argued that logically you want to continue processing at some specific logical point, not to blindly fall through to whatever the heck code happens to be there. Well, if "goto case XXX" is unmaintainable, how about some combination of existing keywords? For example, "continue switch;". -- Best regards, Vladimir mailto:vladimir@thecybershadow.net | |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote: > Jonathan M Davis wrote: >> bearophile wrote: >> >>> 2) switch cases that don't end with goto or break: >>> >>> void main() { >>> int x, y; >>> switch (x) { >>> case 0: y++; >>> default: y--; >>> } >>> } >> >> I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements. > > I agree. But the basic idea is to do extra work if you're doing something unusual, and falling through is unusual. Certainly a good principle and one that D holds to for the most part - certainly far better than many other languages. > > A while ago it was proposed to require each case block to end with a control flow transfer statement (break, continue, return, throw, or goto case XXX). The latter allows fall through in the rare cases that were needed, requiring just a bit of extra umph from the programmer. Perfect solution. > > My recollection of the matter is that Walter rejected the proposal claiming that he uses fall through all the time. Don ran some measurements over Walter's own code and proved him copiously wrong. Walter had no retort to that argument, so he veered into a critique of the goto case XXX solution saying it's unmaintainable: when you moving code around you want to keep on falling through but with goto you'd need to update the goto target. However, it can be argued that logically you want to continue processing at some specific logical point, not to blindly fall through to whatever the heck code happens to be there. > > So ultimately the whole thing fizzled. Apparently the current situation is optimal for programmers who use fall through "all the time", who move code that is fallen into all the time, have weird expectations of code after the move, and never check that jumps are made to the right labels. Requiring goto for fallthrough certainly strikes me as less maintainable (if nothing else because you have to say where you're going - if you could just indicate fallthrough without having to indicate a jump target, it wouldn't really be a problem) but not necessarily unacceptabley so. I use fallthrough often enough that I definitely want to have it, but I'm not rearranging my switch statements so often that having to fix the gotos would be a huge source of errors (though being able to just indicate fallthrough - maybe with just goto with no target, though that could be a problem with the grammar - wouldn't be as big a problem). > > As an aside, I think it's an interesting psychological phenomenon: I think we often have skewed beliefs about the frequency of our patterns. It often happens that switchers to a new language believe they won't be able to make it through the day without feature X (bitfields, anyone? :o)) yet practical experience soon shows otherwise. > > > Andrei It definitely can be interesting. Of course, some of the problem is that there are features that you use semi-often but are easily replaceable while there are other features that you don't necessarily use all that often but would be awful not to have - and knowing what you need ahead of time is often hard. I don't use function pointers all that often, but it can be highly frustrating to program in Java when I could really use a function pointer and don't have one. Of course, that opens up the issue of how useable the feature is as implemented vs how useful it would be if it were useable. I don't use the algorithm library much in C++ because declaring functions or functors to pass to it is just too much of a pain. It's too hard to use for it to be worth it usually. However, D makes that sort of thing much easier with lambdas and inner functions and the like, so I use std.algorithm fairly heavily. In any case, the whole issue of what we really use and what we really need, and how that compares to what we think that we really use and need could probably cover quite a few papers if you really started looking into it. Regardless, whether goto is required for fallthrough in a switch statement or not, I definitely want fallthrough. - Jonathan M Davis | |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Vladimir Panteleev | Vladimir Panteleev wrote:
> Well, if "goto case XXX" is unmaintainable, how about some combination of existing keywords? For example, "continue switch;".
Ooh. I like that. I don't know how well that would work with the grammar, but it's fairly aesthetically pleasing and definitely more maintainable than having to indicate where you're going to - not to mention it makes it distinct from situations where you really want to go to a case other than the next one (which would be yet another source of bugs and confusion if you had to use "goto case XXX" when falling through).
I definitely would be open to "continue switch." It makes sense and should solve the issue fairly well. The only potential issues that I see are how well it would fit into the grammar and convincing Walter.
- Jonathan M Davis
| |||
June 19, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Fri, 18 Jun 2010 20:17:09 -0700, Jonathan M Davis <jmdavisProg@gmail.com> wrote:
> >> I, for one, _want_ case statements to be able to fall through. It would be horribly painful in many cases if they couldn't. Now, requiring a separate statement like fallthrough or somesuch instead of break might not be a bad idea, but requiring that each case end with a break would seriously restrict the usefulness of switch statements.
> >
> > I agree. But the basic idea is to do extra work if you're doing something unusual, and falling through is unusual.
>
> Certainly a good principle and one that D holds to for the most part - certainly far better than many other languages.
>
Follow the principle too much, though, and you end up in the Ruby (more specifically, Rails) camp. It's amazing when you don't need to do something unusual, but *man* have I had problems trying to do what I want with Rails.
That said, having used C for a significant period of time, I'm well aware of the fall-through semantics and use it from time to time, but I wouldn't be opposed to removing implicit fall-through from the language.
Fall-through doesn't strike me as a big issue in and of itself, but dogmatic languages aren't fun to work with either.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply