digitalmars.D - Why do shift operators undergo integral promotion?
- Don (20/20) Aug 09 2011 From a discussion on D.learn.
- Walter Bright (2/22) Aug 09 2011 That last is why we can't just change the behavior from C.
- Jonathan M Davis (8/34) Aug 09 2011 The question though is whether that is ever _desired_ behavior in a C pr...
- so (13/54) Aug 09 2011 Can't we finally get rid of this compatibility issue by separating?
- Andrew Wiley (4/52) Aug 09 2011 That would essentially mean we have two compilers to maintain at the end...
- so (10/19) Aug 09 2011 True, but we are now doing something similar (probably something much
- Jonathan M Davis (21/44) Aug 09 2011 Generally speaking, when C or C++ code compiles as D code, it has identi...
- bearophile (4/10) Aug 09 2011 You are too much quick at dismissing this. There are several advantages ...
- so (29/53) Aug 09 2011 I see having a compiler flag is a bad idea, it would be entirely in the ...
- Jonathan M Davis (18/44) Aug 09 2011 In general, it's not a problem at all. It's only relevant when the C/C++...
- so (7/41) Aug 09 2011 What you are saying just covers the language being a C like language,
- Jonathan M Davis (25/71) Aug 09 2011 ??? One of the rules of language design that Walter has stuck to through...
- so (17/46) Aug 09 2011 I like Walter's ideas on language design and his analysis on other
- Walter Bright (4/6) Aug 09 2011 I don't see any way to make that judgment. It's been Standard C behavior...
- Jonathan M Davis (15/22) Aug 09 2011 Hmmm. It seems to me that the question is whether anyone would ever
- Walter Bright (3/17) Aug 09 2011 I don't see why it's a miracle that s>>1 would yield an int result.
- Jonathan M Davis (9/30) Aug 09 2011 Then I'm misunderstanding something here. It was my understanding that t...
- Timon Gehr (11/41) Aug 09 2011 I think what can be surprising is that s >>> 1 sign-extends s prior to t...
- bearophile (5/8) Aug 09 2011 See:
- KennyTM~ (6/31) Aug 10 2011 Does C or C++ even have a '>>>' operator? If we need to have a
- Don (25/52) Aug 10 2011 ???? C doesn't even have the >>> operator.
From a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x + y), but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }
Aug 09 2011
On 8/9/2011 2:46 AM, Don wrote:From a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x + y), but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }That last is why we can't just change the behavior from C.
Aug 09 2011
On 8/9/2011 2:46 AM, Don wrote:The question though is whether that is ever _desired_ behavior in a C program. If it's always a bug when it happens, then I'd argue that we can and should change the behavior. If there's a legitimate reason why could would want the C behavior, then changing it in D would cause problems for porting code, but if the difference only matters when there's a bug in the C code, then breaking compatibility is only an issue for broken code, and changing it would help prevent issues in D. - Jonathan M DavisFrom a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x + y), but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }That last is why we can't just change the behavior from C.
Aug 09 2011
On Tue, 09 Aug 2011 21:37:18 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote:Can't we finally get rid of this compatibility issue by separating? . for the whole file which can be enabled with a flag to compiler "dmd -Cmode ...." . default it is not enforced, if we desire compatibility we could just write: version(Cmode) // or something better instead of version { } What would be the problem other than the trouble of implementing this? I hate to see the shield of C compatibility against every good idea/solution.On 8/9/2011 2:46 AM, Don wrote:The question though is whether that is ever _desired_ behavior in a C program. If it's always a bug when it happens, then I'd argue that we can and should change the behavior. If there's a legitimate reason why could would want the C behavior, then changing it in D would cause problems for porting code, but if the difference only matters when there's a bug in the C code, then breaking compatibility is only an issue for broken code, and changing it would help prevent issues in D. - Jonathan M DavisFrom a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x +y),but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }That last is why we can't just change the behavior from C.
Aug 09 2011
On Tue, Aug 9, 2011 at 1:10 PM, so <so so.xn--s-fka> wrote:On Tue, 09 Aug 2011 21:37:18 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote: On 8/9/2011 2:46 AM, Don wrote:That would essentially mean we have two compilers to maintain at the end of the day because the semantics of certain operations would depend entirely on whether the compiler was in C mode or not.Can't we finally get rid of this compatibility issue by separating? . for the whole file which can be enabled with a flag to compiler "dmd -Cmode ...."The question though is whether that is ever _desired_ behavior in a C program. If it's always a bug when it happens, then I'd argue that we can and should change the behavior. If there's a legitimate reason why could would want the C behavior, then changing it in D would cause problems for porting code, but if the difference only matters when there's a bug in the C code, then breaking compatibility is only an issue for broken code, and changing it would help prevent issues in D. - Jonathan M DavisFrom a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x + y), but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }That last is why we can't just change the behavior from C.
Aug 09 2011
On Tue, 09 Aug 2011 23:20:02 +0300, Andrew Wiley <wiley.andrew.j gmail.com> wrote:True, but we are now doing something similar (probably something much harder) which unlikely produces a positive outcome. We say there is a compatibility where there was not (to which extend no one knows), on the other hand there are new rules/syntax for the same problems in the same language which would create awful amount of confusion, not to mention ignoring the solutions to the problems. On maintaining two compilers, i don't think this is a bigger issue because C compiler and spec already here and never changes.Can't we finally get rid of this compatibility issue by separating? . for the whole file which can be enabled with a flag to compiler "dmd -Cmode ...."That would essentially mean we have two compilers to maintain at the end of the day because the semantics of certain operations would depend entirely on whether the compiler was in C mode or not.
Aug 09 2011
On Tue, 09 Aug 2011 23:20:02 +0300, Andrew Wiley <wiley.andrew.j gmail.com> wrote:Generally speaking, when C or C++ code compiles as D code, it has identical behavior (there are a few exceptions - such as passing static arrays - but it's almost always true). The reason for this is so that you don't end up with tons of bugs when porting code to D from C or C++. If it weren't for that, then corner cases such as this wouldn't really matter, and we could just make D to the smart thing. But because we don't want code which is ported to break in all kinds of subtle ways, we maintain compatibility with C/C++ as long as the C/C++ code is valid D code. There's no reason to have a separate version of the language which is more compatible with C than another version. It would just complicate things. Not only would it be a burden on the compiler maintainers, but then you would have to know whether code was intended to be compiled with the standard D compiler or with the one which is more compatible with C. It would be a mess for very little benefit. The question here is whether we can safely make the change to D's behavior without breaking code which is ported from C or C++. As long as it is pretty much a guarantee that any code which relies on the C behavior is buggy, then I don't see any reason why we can't fix the behavior in D. However, if there are valid reasons for C code to rely on the C behavior, then we're kind of stuck.True, but we are now doing something similar (probably something much harder) which unlikely produces a positive outcome. We say there is a compatibility where there was not (to which extend no one knows), on the other hand there are new rules/syntax for the same problems in the same language which would create awful amount of confusion, not to mention ignoring the solutions to the problems. On maintaining two compilers, i don't think this is a bigger issue because C compiler and spec already here and never changes.Can't we finally get rid of this compatibility issue by separating? . for the whole file which can be enabled with a flag to compiler "dmd -Cmode ...."That would essentially mean we have two compilers to maintain at the end of the day because the semantics of certain operations would depend entirely on whether the compiler was in C mode or not.From what I can see though, it sure looks like any C code which relies on theC behavior would be buggy. - Jonathan M Davis
Aug 09 2011
Jonathan M Davis:There's no reason to have a separate version of the language which is more compatible with C than another version. It would just complicate things. Not only would it be a burden on the compiler maintainers, but then you would have to know whether code was intended to be compiled with the standard D compiler or with the one which is more compatible with C. It would be a mess for very little benefit.You are too much quick at dismissing this. There are several advantages you aren't even listing. Bye, bearophile
Aug 09 2011
On Wed, 10 Aug 2011 00:08:02 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote:There's no reason to have a separate version of the language which is more compatible with C than another version. It would just complicate things.Not only would it be a burden on the compiler maintainers, but then you would have to know whether code was intended to be compiled with the standard D compiler or with the one which is more compatible with C. It would be a mess for very little benefit.I see having a compiler flag is a bad idea, it would be entirely in the source code. It is not about having more/less compatible compilers. There is only one compiler to be maintained and it is D. Getting rid of such a restriction (C compatibility) would be priceless i can't express, and i don't understand why it is not obvious. Our problem is this very restriction. D should be called "C like (easy to learn if you know C/C++) and supports C natively", not "C compatible". Because if being out of date was the only thing wrong about C then someone would just add some modern features and call it maybe... C++-+%?The question here is whether we can safely make the change to D's behavior without breaking code which is ported from C or C++. As long as it is pretty much a guarantee that any code which relies on the C behavior is buggy, then I don't see any reason why we can't fix the behavior in D. However, if there are valid reasons for C code to rely on the C behavior, then we're kind of stuck.We are falling a trap C didn't. How is it any different than maintaining ASM compatibility in C? But they didn't, they just separated it. They had a very compelling argument, so much more important than ours, that ASM is THE machine itself. Yet they just dropped it. c code: .... asm { .... } and d would be better of like: ... asm { ... } ... C { }From what I can see though, it sure looks like any C code which relies on theC behavior would be buggy.
Aug 09 2011
On Wed, 10 Aug 2011 00:08:02 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote:In general, it's not a problem at all. It's only relevant when the C/C++ code is valid D code. It often isn't. For the most part, the code which is both (the primary exception that I can think of being pointers). It's stuff which is common across C-based languages and would screw over programmers pretty thoroughly if it changed. There are a few exceptions (such as this issue with the shift operator) which are a problem, but for the most part, it's really not an issue. It's trying to maintain C++'s level of compatibility with C where you really get into trouble. D does _not_ maintain anything even close to that level of compatability. It just chooses to be compatible when the syntax is identical so that code which is ported from C or C++ doesn't silently break. So, while from what I can see, I think that in this particular case, it would be a good idea to fix C's behavior rather than follow it, I think that you're blowing the issue of general C compatibility out of proportion. D breaks compatibility all over the place. It just doesn't do it when C code would be valid D code. - Jonathan M DavisThere's no reason to have a separate version of the language which is more compatible with C than another version. It would just complicate things. Not only would it be a burden on the compiler maintainers, but then you would have to know whether code was intended to be compiled with the standard D compiler or with the one which is more compatible with C. It would be a mess for very little benefit.I see having a compiler flag is a bad idea, it would be entirely in the source code. It is not about having more/less compatible compilers. There is only one compiler to be maintained and it is D. Getting rid of such a restriction (C compatibility) would be priceless i can't express, and i don't understand why it is not obvious. Our problem is this very restriction. D should be called "C like (easy to learn if you know C/C++) and supports C natively", not "C compatible". Because if being out of date was the only thing wrong about C then someone would just add some modern features and call it maybe... C++-+%?
Aug 09 2011
On Wed, 10 Aug 2011 00:57:17 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote:What you are saying just covers the language being a C like language, aren't we talking about the restriction and threat it pose to the language?I see having a compiler flag is a bad idea, it would be entirely in the source code. It is not about having more/less compatible compilers. There is only one compiler to be maintained and it is D. Getting rid of such a restriction (C compatibility) would be priceless i can't express, and i don't understand why it is not obvious. Our problem is this very restriction. D should be called "C like (easy to learn if you know C/C++) and supports C natively", not "C compatible". Because if being out of date was the only thing wrong about C then someone would just add some modern features and call it maybe... C++-+%?In general, it's not a problem at all. It's only relevant when the C/C++ code is valid D code. It often isn't. For the most part, the code which is both as well (the primary exception that I can think of being pointers). It's stuff which is common across C-based languages and would screw over programmers pretty thoroughly if it changed. There are a few exceptions (such as this issue with the shift operator) which are a problem, but for the most part, it's really not an issue. It's trying to maintain C++'s level of compatibility with C where you really get into trouble. D does _not_ maintain anything even close to that level of compatability. It just chooses to be compatible when the syntax is identical so that code which is ported from C or C++ doesn't silently break.D breaks compatibility all over the place. It just doesn't do it when C code would be valid D code.I am afraid this is not quite right. Wouldn't it be oxymoron when you reject every solution/idea using this argument? It doesn't matter if the idea has no merit or it was the meaning of life.
Aug 09 2011
On Wed, 10 Aug 2011 00:57:17 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote:??? One of the rules of language design that Walter has stuck to throughout the development of D is that if you take any C or C++ code and try to compile it as D code, it will either fail to compile, or it will compile with the same behavior as the code would have had in C or C++. This is so that you don't silently introduce bugs when porting code from C or C++ to D. There's _lots_ of stuff in D that isn't valid C code, and there's plenty of stuff in C which isn't valid D code. Saying that C/C++ code must either be valid D code with the same behavior or not compile is not particularly restrictive on the whole. It's really only an issue with some arithmetic stuff. D is free to add additional restrictions (such as requiring casts for narrowing conversions), and it can do whatever it wants which is different from C as long as it isn't valid C - and almost everything that D does is different enough that it's almost a non-issue. You'd actually probably have a hard time trying to come up with a feature to introduce to the language which would be valid C but have different behavior in D than C. The common stuff is the really basic stuff like arithmetic and pointers, which isn't really where you're going to be adding features. The only issue with it really is that there are a few rough edges in C with regards to arithmetic. Anyone looking for a drastically different way of handling math between different integer types, for instance, is going to be out of luck. But there's not much beyond that which is strictly compatible with C. D is just too different from C for that small amount of compatibility to be much of an issue. It does crop up periodically but not often, and it's a whole world of difference from how C++ treats compatibility with C. - Jonathan M DavisWhat you are saying just covers the language being a C like language, aren't we talking about the restriction and threat it pose to the language?I see having a compiler flag is a bad idea, it would be entirely in the source code. It is not about having more/less compatible compilers. There is only one compiler to be maintained and it is D. Getting rid of such a restriction (C compatibility) would be priceless i can't express, and i don't understand why it is not obvious. Our problem is this very restriction. D should be called "C like (easy to learn if you know C/C++) and supports C natively", not "C compatible". Because if being out of date was the only thing wrong about C then someone would just add some modern features and call it maybe... C++-+%?In general, it's not a problem at all. It's only relevant when the C/C++ code is valid D code. It often isn't. For the most part, the code which is both as well (the primary exception that I can think of being pointers). It's stuff which is common across C-based languages and would screw over programmers pretty thoroughly if it changed. There are a few exceptions (such as this issue with the shift operator) which are a problem, but for the most part, it's really not an issue. It's trying to maintain C++'s level of compatibility with C where you really get into trouble. D does _not_ maintain anything even close to that level of compatability. It just chooses to be compatible when the syntax is identical so that code which is ported from C or C++ doesn't silently break.D breaks compatibility all over the place. It just doesn't do it when C code would be valid D code.I am afraid this is not quite right. Wouldn't it be oxymoron when you reject every solution/idea using this argument? It doesn't matter if the idea has no merit or it was the meaning of life.
Aug 09 2011
On Wed, 10 Aug 2011 01:36:58 +0300, Jonathan M Davis <jmdavisProg gmx.com> wrote:??? One of the rules of language design that Walter has stuck to throughout the development of D is that if you take any C or C++ code and try to compile it as D code, it will either fail to compile, or it will compile with the same behavior as the code would have had in C or C++. This is so that you don't silently introduce bugs when porting code from C or C++ to D.I like Walter's ideas on language design and his analysis on other languages, this is not one of them. I don't understand what purpose it does serve.There's _lots_ of stuff in D that isn't valid C code, and there's plenty of stuff in C which isn't valid D code. Saying that C/C++ code must either be valid D code with the same behavior or not compile is not particularly restrictive on the whole.You are missing the point. You'd be right if D being C like was a strange consequence (we did everything as it should be done, did not repeat other languages mistakes, funny enough a C code compiles like it is a D code) rather than the result of some restriction (which would have only one outcome) in design.It's really only an issue with some arithmetic stuff. D is free to add additional restrictions (such as requiring casts for narrowing conversions), and it can do whatever it wants which is different from C as long as it isn't valid C - and almost everything that D does is different enough that it's almost a non-issue.Free to add but on what criteria?You'd actually probably have a hard time trying to come up with a feature to introduce to the language which would be valid C but have different behavior in D than C. The common stuff is the really basic stuff like arithmetic and pointers, which isn't really where you're going to be adding features.Funny enough it wouldn't be that hard find, my first appearance in this list was exactly on this issue. Remember there was no templates in C, and C numerics was designed for that environment which is far from D. Separation would be great help but i am afraid it is getting late for D. We know the consensus for major changes, especially at this stage.
Aug 09 2011
On 8/9/2011 2:08 PM, Jonathan M Davis wrote:From what I can see though, it sure looks like any C code which relies on the C behavior would be buggy.I don't see any way to make that judgment. It's been Standard C behavior forever, including K+R prehistory. It's guaranteed that a lot of code will rely on it, whether or not anyone considers it good form.
Aug 09 2011
On 8/9/2011 2:08 PM, Jonathan M Davis wrote:Hmmm. It seems to me that the question is whether anyone would ever _intentially_ use this behavior. Is there any benefit to it whatsoever? If not, I'd argue that the risk of breakage to C code being ported over is minimal and that the behavior should be fixed in D. Now, if there _is_ a benefit to it such that someone would use it intentionally, then that's another story, but it sure likes like the only reason that it would occur in C code would be because the programmer who wrote it screwed up. Now, that's still going to change the behavior of any code which used this behavior - even if it was by accident - which risks making code fail to work even if it only worked through a miracle before (i.e. in spite of the bug). So, maybe that's enough that we can't fix it. But it sure seems like the risk of new breakage is very low, since code whose behavior would change was broken in the first place, and I'd hate to see D's behavior stay like this if we can fix it. - Jonathan M DavisFrom what I can see though, it sure looks like any C code which relies on the C behavior would be buggy.I don't see any way to make that judgment. It's been Standard C behavior forever, including K+R prehistory. It's guaranteed that a lot of code will rely on it, whether or not anyone considers it good form.
Aug 09 2011
On 8/9/2011 3:04 PM, Jonathan M Davis wrote:Hmmm. It seems to me that the question is whether anyone would ever _intentially_ use this behavior. Is there any benefit to it whatsoever? If not, I'd argue that the risk of breakage to C code being ported over is minimal and that the behavior should be fixed in D. Now, if there _is_ a benefit to it such that someone would use it intentionally, then that's another story, but it sure likes like the only reason that it would occur in C code would be because the programmer who wrote it screwed up. Now, that's still going to change the behavior of any code which used this behavior - even if it was by accident - which risks making code fail to work even if it only worked through a miracle before (i.e. in spite of the bug). So, maybe that's enough that we can't fix it. But it sure seems like the risk of new breakage is very low, since code whose behavior would change was broken in the first place, and I'd hate to see D's behavior stay like this if we can fix it.I don't see why it's a miracle that s>>1 would yield an int result. Do any of the C lints flag this as a bad practice?
Aug 09 2011
On 8/9/2011 3:04 PM, Jonathan M Davis wrote:Then I'm misunderstanding something here. It was my understanding that this was yielding results which pretty much any programmer would consider incorrect or undesirable. As such, when this issue pops up, it yields an incorrect result, so the code is broken, and if it works, it's because something else gets around the issue (hence the miracle). If this isn't actually yielding effectively incorrect results, then it's a different issue entirely. So, I'm obviously misunderstanding exactly what the issue is - probably at least in part because I rarely need to use bitshifts. - Jonathan M DavisHmmm. It seems to me that the question is whether anyone would ever _intentially_ use this behavior. Is there any benefit to it whatsoever? If not, I'd argue that the risk of breakage to C code being ported over is minimal and that the behavior should be fixed in D. Now, if there _is_ a benefit to it such that someone would use it intentionally, then that's another story, but it sure likes like the only reason that it would occur in C code would be because the programmer who wrote it screwed up. Now, that's still going to change the behavior of any code which used this behavior - even if it was by accident - which risks making code fail to work even if it only worked through a miracle before (i.e. in spite of the bug). So, maybe that's enough that we can't fix it. But it sure seems like the risk of new breakage is very low, since code whose behavior would change was broken in the first place, and I'd hate to see D's behavior stay like this if we can fix it.I don't see why it's a miracle that s>>1 would yield an int result. Do any of the C lints flag this as a bad practice?
Aug 09 2011
Jonathan M Davis wrote:Walter Bright wrote:was yielding results which pretty much any programmer would considerOn 8/9/2011 3:04 PM, Jonathan M Davis wrote:Then I'm misunderstanding something here. It was my understanding that this >Hmmm. It seems to me that the question is whether anyone would ever _intentially_ use this behavior. Is there any benefit to it whatsoever? If not, I'd argue that the risk of breakage to C code being ported over is minimal and that the behavior should be fixed in D. Now, if there _is_ a benefit to it such that someone would use it intentionally, then that's another story, but it sure likes like the only reason that it would occur in C code would be because the programmer who wrote it screwed up. Now, that's still going to change the behavior of any code which used this behavior - even if it was by accident - which risks making code fail to work even if it only worked through a miracle before (i.e. in spite of the bug). So, maybe that's enough that we can't fix it. But it sure seems like the risk of new breakage is very low, since code whose behavior would change was broken in the first place, and I'd hate to see D's behavior stay like this if we can fix it.I don't see why it's a miracle that s>>1 would yield an int result. Do any of the C lints flag this as a bad practice?incorrect or undesirable. As such, when this issue pops up, it yields an incorrect result, so the code is broken, and if it works, it's because something else gets around the issue (hence the miracle). If this isn't actually yielding effectively incorrect results, then it's a different issue entirely. So, I'm obviously misunderstanding exactly what the issue is - probably at least in part because I rarely need to use bitshifts. - Jonathan M DavisI think what can be surprising is that s >>> 1 sign-extends s prior to the unsigned right shift. void main() { short s=-1; assert(s>>>1 == 2147483647); s=-1; s>>>=1; writeln(s == 32767); }
Aug 09 2011
so:Can't we finally get rid of this compatibility issue by separating? . for the whole file which can be enabled with a flag to compiler "dmd -Cmode ...."See: http://d.puremagic.com/issues/show_bug.cgi?id=4580 Bye, bearophile
Aug 09 2011
On Aug 10, 11 01:06, Walter Bright wrote:On 8/9/2011 2:46 AM, Don wrote:Does C or C++ even have a '>>>' operator? If we need to have a type-promotion rule like C, it could be made as x >>> y == cast(promoted type) cast(typeof(x)) (unsigned(x) >> y) e.g. cast(short)(-1) >>> 1 == 0x7f.From a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x + y), but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }That last is why we can't just change the behavior from C.
Aug 10 2011
Walter Bright wrote:On 8/9/2011 2:46 AM, Don wrote:???? C doesn't even have the >>> operator. There is no valid "backwards compatibility with C" argument here. I cannot see ANY justification whatsoever for the behaviour of >>>. Applying integral promotion to >>> is completely wrong. It is a bug in 100% of cases. Possibilities are: (1) use typeof( x >>> y) is typeof(x) (2) as (1), but break with C, and apply the same rule for typeof(x>>y) (The C rule isn't too unreasonable for x << y). (3) generate a compile error for x >>> y when x is short or byte. Actually, I found that I misread the spec. It actually says: "The operands must be integral types, and undergo the usual integral promotions. The result type is the type of the left operand after the promotions. The result value is the result of shifting the bits by the right operand's value." So with x >>> y, the type of y actually has no effect; if x is smaller than int, the result is int; otherwise, the type is x. So in fact, if x is short or byte, then x >>> y is NEVER an unsigned shift, regardless of what y is: it's always the same as x >> y. But the spec says >>> performs an unsigned shift. This disagrees with the >>>= operator as well: >>>= always performs an unsigned shift, even though the spec says that x >>>= y is the same as x = x >>> y. Given that >>> is the same as >> for any unsigned typeFrom a discussion on D.learn. If x and y are different integral types, then in an expression like x >> y the integral promotion rules are applied to x and y. This behaviour is obviously inherited from C, but why did C use such a counter-intuitive and bug-prone rule? Why isn't typeof(x >> y) simply typeof(x) ? What would break if it did? You might think the the rule is that typeof( x >> y) is typeof( x + y), but it isn't: the arithmetic conversions are NOT applied: typeof(int >> long) is int, not long, BUT typeof(short >> int) is int. And we have this death trap (bug 2809): void main() { short s = -1; ushort u = s; assert( u == s ); assert ( (s >>> 1) == (u >>> 1) ); // FAILS }That last is why we can't just change the behavior from C.
Aug 10 2011