| Thread overview | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 18, 2010 Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
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. | ||||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | Don <nospam@nospam.com> wrote: > I was quite shocked to find that the reason is backwards compatibility with the B programming language. Surely it is important that all B code ported to D compiles correctly? :p But yes, end the madness. I fear Walter will only do it if it provably breaks no code, though. I just thought through this agin. WTF? -- Simen | |||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Simen kjaeraas | Dnia 18-06-2010 o 23:11:43 Simen kjaeraas <simen.kjaras@gmail.com> napisał(a):
> But yes, end the madness. I fear Walter will only do it if it provably
> breaks no code, though.
if (a==b & c) would be flagged as error. If it breaks loudly, that's ok. Besides, it's not much used anyway. Ban it.
Tomek
| |||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | Don wrote:
[snip]
> Or is too late to break backwards compatibility with B ?
We can and should do it. It won't impact TDPL adversely.
A perhaps little known thing is that D doesn't allow this:
int a, b, c;
if (a < b < c) { ... }
although it's compilable code in C. The same strategy could be used for combinations of badly-prioritized operators: the language could just require the user to add parens.
Andrei
| |||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | Don: > 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. You can change the dmd compiler (even D1, if you want) applying this change and create a compiled "experiment version" that people can try (even people that don't compile dmd every day), to see possible side effects of this change, use it to spot bugs in their D code or inside Phobos, etc. > BTW I think this a great cautionary tale about the dangers of rating backwards compatibility too highly. Beside that one, there are few other parts of C/D code that I'd like still to turn into syntax errors in D2, like: 1) Implicit string concat (bug 3827, with an incomplete patch): string[] a = ["foo", "bar" "baz"]; 2) switch cases that don't end with goto or break: void main() { int x, y; switch (x) { case 0: y++; default: y--; } } 3) Several usages of C comma operator. And few others that I don't remember now. ---------------- Andrei Alexandrescu: > A perhaps little known thing is that D doesn't allow this: > int a, b, c; > if (a < b < c) { ... } > although it's compilable code in C. It's a pity C compatibily forbids to use that syntax in D, because chained comparison operator syntax is handy in Python to tell if a value is in a range: >>> 1 < 5 < 10 True >>> "hello" < "zeta" < "red" False Bye, bearophile | |||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile:
> >>> 1 < 5 < 10
> True
It's especially useful when the value in the middle is the result of some function call:
if 1 < foo(5) < 10: ...
In D you have to use a temporary variable:
auto aux = foo(5);
if (1 < aux && aux < 10) { ...
Bye,
bearophile
| |||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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.
- Jonathan M Davis
| |||
June 18, 2010 Re: Is there ANY chance we can fix the bitwise operator precedence rules? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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
| |||
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:
>> 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
| |||
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:
...
> 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.
...
Yikes, that should be "using the same _code_."
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply