digitalmars.D - Thoughts on some code breakage with 2.074
- Brian Schott (8/8) May 08 2017 Recently the EMSI data department upgraded the compiler we use to
- Adam Wilson (16/23) May 09 2017 WUT.
- David Eckardt (11/16) May 09 2017 Here is more of this. Writing industry D code I *love* breaking
- H. S. Teoh via Digitalmars-d (25/49) May 09 2017 [...]
- Patrick Schluter (4/15) May 09 2017 The code breakage annoyance has more to do with 3rd party
- Adam Wilson (28/44) May 09 2017 *cough* Umm, I think that's a false pointer.
- H. S. Teoh via Digitalmars-d (18/32) May 09 2017 [...]
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/17) May 10 2017 Can you show an example please. I don't see this being required by
- Jonathan M Davis via Digitalmars-d (6/26) May 10 2017 I think that that's the one that Andrei and Vladimir didn't like, becaus...
- =?UTF-8?Q?Ali_=c3=87ehreli?= (6/15) May 10 2017 Bummer for H. S. Teoh I guess... :/
- Jonathan M Davis via Digitalmars-d (12/31) May 10 2017 The big problems is dynamic arrays, not pointers, which was what I thoug...
- deadalnix (3/7) May 11 2017 All bool conversions in D are value based, not identity based.
- Steven Schveighoffer (9/18) May 11 2017 What does "value based" and "identity based" mean?
- deadalnix (7/8) May 11 2017 Nope. It is:
- Steven Schveighoffer (18/24) May 11 2017 Yep, you are right. It's checking the length too. Although in practice,
- Steven Schveighoffer (4/10) May 11 2017 But this still doesn't mean that *all* bool conversions are value based....
- H. S. Teoh via Digitalmars-d (34/37) May 11 2017 [...]
- Steven Schveighoffer (12/41) May 12 2017 I have totally misremembered the thing of classes and invariants. So my
- Patrick Schluter (15/35) May 11 2017 Yes, me too (in C). It is conceptually imho ok to use it that way
- Steven Schveighoffer (13/39) May 11 2017 I think that was the if(array) fiasco.
- deadalnix (4/8) May 11 2017 It is not a problem for pointer because for pointer identity and
- H. S. Teoh via Digitalmars-d (38/52) May 11 2017 [...]
Recently the EMSI data department upgraded the compiler we use to build our data processing code to 2.074. This caused several of the thousands of processes to die with signal 8 (floating point exceptions). This was caused by the fix to issue 17243. This is a good thing. We need more breaking changes like this. Now that the floating point exceptions are properly enabled we were able to track down some issues that were being silently ignored.
May 08 2017
On 5/8/17 20:33, Brian Schott wrote:Recently the EMSI data department upgraded the compiler we use to build our data processing code to 2.074. This caused several of the thousands of processes to die with signal 8 (floating point exceptions). This was caused by the fix to issue 17243. This is a good thing. We need more breaking changes like this. Now that the floating point exceptions are properly enabled we were able to track down some issues that were being silently ignored.WUT. All I hear on these forums is the abject terror of breaking changes making companies run screaming from D. You mean to say that companies don't actually mind breaking changes if it solves long-standing issues. I'm shocked. SHOCKED I SAY! ;-) Can we PLEASE get more of this? I'm not saying up-end the language, but let's solve some problems. I doubt our corporate users will be very angry. I suspect that most reactions will fall between "minor irritation" and this one. /me looks sideways at shared -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
May 09 2017
On Tuesday, 9 May 2017 at 12:13:34 UTC, Adam Wilson wrote:Can we PLEASE get more of this? I'm not saying up-end the language, but let's solve some problems. I doubt our corporate users will be very angry. I suspect that most reactions will fall between "minor irritation" and this one. /me looks sideways at sharedHere is more of this. Writing industry D code I *love* breaking changes that reveal bugs in the code base. A while ago I suggested changing cast(bool) semantics of floating-point types so that assert(x) fails if x is NaN (https://issues.dlang.org/show_bug.cgi?id=13489). It was rejected because it could break existing code and surprise C/C++ programmers (although the point of NaN is to surprise you IMHO). I wonder what the ratio of valid to buggy code is that would break with this change. At least I enjoy it if my buggy code breaks.
May 09 2017
On Tue, May 09, 2017 at 02:13:34PM +0200, Adam Wilson via Digitalmars-d wrote:On 5/8/17 20:33, Brian Schott wrote:[...]Recently the EMSI data department upgraded the compiler we use to build our data processing code to 2.074. This caused several of the thousands of processes to die with signal 8 (floating point exceptions). This was caused by the fix to issue 17243. This is a good thing. We need more breaking changes like this.WUT. All I hear on these forums is the abject terror of breaking changes making companies run screaming from D. You mean to say that companies don't actually mind breaking changes if it solves long-standing issues. I'm shocked. SHOCKED I SAY! ;-) Can we PLEASE get more of this? I'm not saying up-end the language, but let's solve some problems. I doubt our corporate users will be very angry. I suspect that most reactions will fall between "minor irritation" and this one. /me looks sideways at shared[...] I don't represent any company, but I have to also say that I *appreciate* breaking changes that reveal latent bugs in my code. In fact, I even appreciate breakages that eventually force me to write more readable code! A not-so-recent example: /* Used to work, oh, I forget which version now, but it used to * work: */ MyType* ptr = ...; if (someCondition && ptr) { ... } After upgrading the compiler, I get a warning that using a pointer as a condition is deprecated. At first I was mildly annoyed... but then to make the warning go away, I wrote this instead: /* Look, ma! Self-documenting, readable code! */ MyType* ptr = ...; if (someCondition && ptr !is null) { ... } Much more readable, and makes intent so much clearer. Eventually I was very happy this supposedly "big bad" breaking change was made. I wish Walter & Andrei & gang would introduce this sort of breakages more often. They will both improve the language and impress users whose code we are so afraid of breaking (I'm still not sure why). T -- Stop staring at me like that! It's offens... no, you'll hurt your eyes!
May 09 2017
On Tuesday, 9 May 2017 at 17:34:48 UTC, H. S. Teoh wrote:On Tue, May 09, 2017 at 02:13:34PM +0200, Adam Wilson via Digitalmars-d wrote:The code breakage annoyance has more to do with 3rd party libraries not very actively maintained than with active codebases imho.[...][...][...][...] I don't represent any company, but I have to also say that I *appreciate* breaking changes that reveal latent bugs in my code. In fact, I even appreciate breakages that eventually force me to write more readable code! A not-so-recent example: [...]
May 09 2017
On 5/9/17 20:23, Patrick Schluter wrote:On Tuesday, 9 May 2017 at 17:34:48 UTC, H. S. Teoh wrote:*cough* Umm, I think that's a false pointer. If it's not actively maintained, should you really be relying on it? Where I work, current maintenance is one of the first questions we ask, followed immediately by determining whether or not we are able to maintain it ourselves should it go unmaintained. If you're going to take on maintenance yourself, the library is already missing features and you're responsible for fixing it's existing implementation bugs anyways, might as well do the work of upgrading it while you're at it. This is the point of Open Source, we have the opportunity to take unmaintained code and start maintaining it again. Either way all I hear about is corp users not liking breaking changes. That has been demonstrated as a false concern time and time again. If it's a matter of unmaintained libraries, those libraries probably have bigger problems than breaking compiler changes, fork and upgrade them or write your own. Because those have always been the only two choices you've ever had in practice anyways. Telling the world that we can't make breaking changes to the compiler because it might break an unmaintained library is irrational position and extreme position to take. It will *not* win us hearts and minds. Let's stop hiding behind our misplaced fears over corp-users and unmaintained libraries so that we can start improving D for everyone who is using it today. -- Adam Wilson IRC: LightBender import quiet.dlang.dev;On Tue, May 09, 2017 at 02:13:34PM +0200, Adam Wilson via Digitalmars-d wrote:The code breakage annoyance has more to do with 3rd party libraries not very actively maintained than with active codebases imho.[...][...][...][...] I don't represent any company, but I have to also say that I *appreciate* breaking changes that reveal latent bugs in my code. In fact, I even appreciate breakages that eventually force me to write more readable code! A not-so-recent example: [...]
May 09 2017
On Wed, May 10, 2017 at 03:19:20AM +0200, Adam Wilson via Digitalmars-d wrote: [...]Either way all I hear about is corp users not liking breaking changes. That has been demonstrated as a false concern time and time again. If it's a matter of unmaintained libraries, those libraries probably have bigger problems than breaking compiler changes, fork and upgrade them or write your own. Because those have always been the only two choices you've ever had in practice anyways. Telling the world that we can't make breaking changes to the compiler because it might break an unmaintained library is irrational position and extreme position to take. It will *not* win us hearts and minds. Let's stop hiding behind our misplaced fears over corp-users and unmaintained libraries so that we can start improving D for everyone who is using it today.[...] +1. Please let's not go down the same path that led C++ to become what it is today: an overly complex language that almost nobody fully understands (and even fewer can write correct code in), yet still suffering under the weight of design mistakes of decades ago. But in spite of all that, it's, oh, backward-compatible! How wonderful, I can still compile my horribly-broken, memory-leaking, pointer-bug-infested excuse for code that I wrote when I was still in college! Isn't that great? Oh wait, it just segfaulted. No biggie, I can fix that easily ... give gimme a minute... uh... um... OK, WHAT has changed since the 90's that I can't do *this* anymore? (5 hours later) I give up, this code is useless. Why does C++ still bother supporting this crappy excuse for code after 2 decades?! T -- Skill without imagination is craftsmanship and gives us many useful objects such as wickerwork picnic baskets. Imagination without skill gives us modern art. -- Tom Stoppard
May 09 2017
On 05/09/2017 10:34 AM, H. S. Teoh via Digitalmars-d wrote:I even appreciate breakages that eventually force me to write more readable code! A not-so-recent example: /* Used to work, oh, I forget which version now, but it used to * work: */ MyType* ptr = ...; if (someCondition && ptr) { ... } After upgrading the compiler, I get a warning that using a pointer as a condition is deprecated. At first I was mildly annoyed... but then to make the warning go away, I wrote this instead: /* Look, ma! Self-documenting, readable code! */ MyType* ptr = ...; if (someCondition && ptr !is null) { ... }Can you show an example please. I don't see this being required by 2.074.0 (compiled with -w -de). Thank you, Ali
May 10 2017
On Wednesday, May 10, 2017 05:05:59 Ali Çehreli via Digitalmars-d wrote:On 05/09/2017 10:34 AM, H. S. Teoh via Digitalmars-d wrote: > I even appreciate breakages that eventually force me to write more > > readable code! A not-so-recent example: > /* Used to work, oh, I forget which version now, but it used to > > * work: */ > > MyType* ptr = ...; > if (someCondition && ptr) { ... } > > After upgrading the compiler, I get a warning that using a pointer as a > condition is deprecated. At first I was mildly annoyed... but then to > > make the warning go away, I wrote this instead: > /* Look, ma! Self-documenting, readable code! */ > MyType* ptr = ...; > if (someCondition && ptr !is null) { ... } Can you show an example please. I don't see this being required by 2.074.0 (compiled with -w -de).I think that that's the one that Andrei and Vladimir didn't like, because they actually used the conversion to bool correctly in their code a bunch (whereas most everyone else thought that it was too error prone), and the deprecation ended up being removed. - Jonathan M Davis
May 10 2017
On 05/10/2017 11:49 AM, Jonathan M Davis via Digitalmars-d wrote:On Wednesday, May 10, 2017 05:05:59 Ali Çehreli via Digitalmars-d wrote:On 05/09/2017 10:34 AM, H. S. Teoh via Digitalmars-d wrote:pointer as a> After upgrading the compiler, I get a warning that using a> condition is deprecated.I think that that's the one that Andrei and Vladimir didn't like, because they actually used the conversion to bool correctly in their code a bunch (whereas most everyone else thought that it was too error prone), and the deprecation ended up being removed. - Jonathan M DavisBummer for H. S. Teoh I guess... :/ Although I prefer explicit over implicit in most cases, I've never graduated from if(p) and still using it happily. :) Ali
May 10 2017
On Wednesday, May 10, 2017 12:06:40 Ali Çehreli via Digitalmars-d wrote:On 05/10/2017 11:49 AM, Jonathan M Davis via Digitalmars-d wrote: > On Wednesday, May 10, 2017 05:05:59 Ali Çehreli via Digitalmars-dwrote:>> On 05/09/2017 10:34 AM, H. S. Teoh via Digitalmars-d wrote: >> > After upgrading the compiler, I get a warning that using a pointer as a >> > condition is deprecated. > > I think that that's the one that Andrei and Vladimir didn't like, > because > they actually used the conversion to bool correctly in their code a > bunch > (whereas most everyone else thought that it was too error prone), and > the > deprecation ended up being removed. > > - Jonathan M Davis Bummer for H. S. Teoh I guess... :/ Although I prefer explicit over implicit in most cases, I've never graduated from if(p) and still using it happily. :)The big problems is dynamic arrays, not pointers, which was what I thought that H. S. Teoh was talking about (apparently, I read over what he said too quickly). I don't know about deprecations with pointers and if statements, and I use pointers sparingly enough in D that I don't know how long it would be before I'd notice if it _were_ deprecated. But with dynamic arrays, it checks for null, not for empty, and a bunch of folks tend to assume that it checks for empty. Using dynamic arrays directly in if conditions is what had been deprecated (on the theory that it was too error-prone) and what Andrei and Vladimir were unhappy about. - Jonathan M Davis
May 10 2017
On Wednesday, 10 May 2017 at 19:06:40 UTC, Ali Çehreli wrote:Bummer for H. S. Teoh I guess... :/ Although I prefer explicit over implicit in most cases, I've never graduated from if(p) and still using it happily. :) AliAll bool conversions in D are value based, not identity based. Not only this is error prone, this is inconsistent.
May 11 2017
On 5/11/17 5:37 AM, deadalnix wrote:On Wednesday, 10 May 2017 at 19:06:40 UTC, Ali Çehreli wrote:What does "value based" and "identity based" mean? bool conversions vary widely and allow a lot of flexibility (at least for structs): if(arr) -> same as if(arr.ptr) if(someInt) -> same as if(someInt != 0) if(someObject) -> if(someObject !is null && someObject.invariant) if(someStruct) -> if(someStruct.opCast!(bool)) -SteveBummer for H. S. Teoh I guess... :/ Although I prefer explicit over implicit in most cases, I've never graduated from if(p) and still using it happily. :) AliAll bool conversions in D are value based, not identity based. Not only this is error prone, this is inconsistent.
May 11 2017
On Thursday, 11 May 2017 at 12:26:11 UTC, Steven Schveighoffer wrote:if(arr) -> same as if(arr.ptr)Nope. It is: if(arr) -> same as if(((cast(size_t) arr.ptr) | arr.length) != 0) Should we conclude from the fact that absolutely nobody gets it right in this very forum that nobody will get it right outside ? I'll let you judge.
May 11 2017
On 5/11/17 7:12 PM, deadalnix wrote:On Thursday, 11 May 2017 at 12:26:11 UTC, Steven Schveighoffer wrote:Yep, you are right. It's checking the length too. Although in practice, almost never do you have a null pointer array with non-zero length. Just for your amusement, I wrote the test this way :) Stevens-MacBook-Pro:testd steves$ cat testifarrptr.d void main() { char[] x = null; x = x.ptr[0 .. 1]; if(x) { import std.stdio; writeln("ok, deadalnix was right"); } } Stevens-MacBook-Pro:testd steves$ dmd -run testifarrptr.d ok, deadalnix was right -Steveif(arr) -> same as if(arr.ptr)Nope. It is: if(arr) -> same as if(((cast(size_t) arr.ptr) | arr.length) != 0) Should we conclude from the fact that absolutely nobody gets it right in this very forum that nobody will get it right outside ? I'll let you judge.
May 11 2017
On 5/11/17 7:12 PM, deadalnix wrote:On Thursday, 11 May 2017 at 12:26:11 UTC, Steven Schveighoffer wrote:But this still doesn't mean that *all* bool conversions are value based. In at least the struct and class cases, more than just the bits are checked. -Steveif(arr) -> same as if(arr.ptr)Nope. It is: if(arr) -> same as if(((cast(size_t) arr.ptr) | arr.length) != 0) Should we conclude from the fact that absolutely nobody gets it right in this very forum that nobody will get it right outside ? I'll let you judge.
May 11 2017
On Thu, May 11, 2017 at 07:46:24PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]But this still doesn't mean that *all* bool conversions are value based. In at least the struct and class cases, more than just the bits are checked.[...] Wait, what? You can use a *struct* as a bool condition?! I tried this: import std.stdio; struct S {} void main() { S s; if (s) { writeln("WAT"); } } But the compiler (rightly) said: test.d(5): Error: expression s of type S does not have a boolean value Or were you talking about structs that define opCast!bool? (In which case it's certainly intentional and doesn't pose a problem.) I can see classes being usable in conditions, though, since they're essentially pointers hiding behind an abstraction. Still, it doesn't quite sit right with me. For example: class C { } class D { bool opCast(T : bool)() { return false; } } void main() { C c; D d = new D; if (!c) { ... } // OK, expected semantics if (!d) { ... } // *** What happens here? } Whereas had the last two lines been written: if (c is null) { ... } if (d is null) { ... } the intent would be much clearer. (And of course, d would be usable without "is null" if you actually intended to invoke opCast!bool.) T -- In a world without fences, who needs Windows and Gates? -- Christian Surchi
May 11 2017
On 5/11/17 7:52 PM, H. S. Teoh via Digitalmars-d wrote:On Thu, May 11, 2017 at 07:46:24PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]Yes, I was talking about that.But this still doesn't mean that *all* bool conversions are value based. In at least the struct and class cases, more than just the bits are checked.[...] Wait, what? You can use a *struct* as a bool condition?! I tried this: import std.stdio; struct S {} void main() { S s; if (s) { writeln("WAT"); } } But the compiler (rightly) said: test.d(5): Error: expression s of type S does not have a boolean value Or were you talking about structs that define opCast!bool? (In which case it's certainly intentional and doesn't pose a problem.)I can see classes being usable in conditions, though, since they're essentially pointers hiding behind an abstraction. Still, it doesn't quite sit right with me. For example: class C { } class D { bool opCast(T : bool)() { return false; } } void main() { C c; D d = new D; if (!c) { ... } // OK, expected semantics if (!d) { ... } // *** What happens here? }I have totally misremembered the thing of classes and invariants. So my statement on that is wrong. It's when you *assert* a class instance that the invariant is checked, not when used in an if condition. Testing out your question, the opCast to bool doesn't apply for classes. Just the reference is checked against null. You have to write cast(bool)d to trigger the opCast. So classes are just like pointers. Really only structs offer some semblance of control for use in if statements. -Steve
May 12 2017
On Wednesday, 10 May 2017 at 19:06:40 UTC, Ali Çehreli wrote:On 05/10/2017 11:49 AM, Jonathan M Davis via Digitalmars-d wrote:Yes, me too (in C). It is conceptually imho ok to use it that way as a pointer does have a boolean semantic, either it is a valid pointer or it is not. The value of the pointer itself is only in special cases relevant (cases in which they have to be converted to an integral type anyway) and is in any case extremely machine dependent. One can even make the case that checking "ptr !is null" or in C "ptr != 0" is inconsistent as it is the only operation where the value of a pointer is used, which is, at least for C a source of confusion. The 0 value in a pointer context will not necessarily compile to a 0 value in the generated assembly. Some machines have null ptrs that are not represented by 0 bits integral values and the C standard has to take these (granted obsolete) into account.On Wednesday, May 10, 2017 05:05:59 Ali Çehreli viaDigitalmars-d wrote:On 05/09/2017 10:34 AM, H. S. Teoh via Digitalmars-d wrote:a pointer as a> After upgrading the compiler, I get a warning that using> condition is deprecated.I think that that's the one that Andrei and Vladimir didn'tlike, becausethey actually used the conversion to bool correctly in theircode a bunch(whereas most everyone else thought that it was too errorprone), and thedeprecation ended up being removed. - Jonathan M DavisBummer for H. S. Teoh I guess... :/ Although I prefer explicit over implicit in most cases, I've never graduated from if(p) and still using it happily. :)
May 11 2017
On 5/10/17 2:49 PM, Jonathan M Davis via Digitalmars-d wrote:On Wednesday, May 10, 2017 05:05:59 Ali Çehreli via Digitalmars-d wrote:I think that was the if(array) fiasco. I don't ever remember if(ptr) being deprecated. In fact, I'd go as far as saying that maybe H.S. Teoh misremembers the array thing as pointers. The biggest reason is that a huge useful pattern with this is: if(auto x = key in someAA) { // use *x without more hash lookup costs. } I can't imagine anyone attempted to force this to break without a loud backlash. I think if(ptr) is mostly universally understood to mean the pointer is not null. -SteveOn 05/09/2017 10:34 AM, H. S. Teoh via Digitalmars-d wrote: > I even appreciate breakages that eventually force me to write more > > readable code! A not-so-recent example: > /* Used to work, oh, I forget which version now, but it used to > > * work: */ > > MyType* ptr = ...; > if (someCondition && ptr) { ... } > > After upgrading the compiler, I get a warning that using a pointer as a > condition is deprecated. At first I was mildly annoyed... but then to > > make the warning go away, I wrote this instead: > /* Look, ma! Self-documenting, readable code! */ > MyType* ptr = ...; > if (someCondition && ptr !is null) { ... } Can you show an example please. I don't see this being required by 2.074.0 (compiled with -w -de).I think that that's the one that Andrei and Vladimir didn't like, because they actually used the conversion to bool correctly in their code a bunch (whereas most everyone else thought that it was too error prone), and the deprecation ended up being removed.
May 11 2017
On Thursday, 11 May 2017 at 12:21:46 UTC, Steven Schveighoffer wrote:I can't imagine anyone attempted to force this to break without a loud backlash. I think if(ptr) is mostly universally understood to mean the pointer is not null. -SteveIt is not a problem for pointer because for pointer identity and equality are the same thing. It isn't for slices.
May 11 2017
On Thu, May 11, 2017 at 08:21:46AM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]I don't ever remember if(ptr) being deprecated. In fact, I'd go as far as saying that maybe H.S. Teoh misremembers the array thing as pointers. The biggest reason is that a huge useful pattern with this is: if(auto x = key in someAA) { // use *x without more hash lookup costs. } I can't imagine anyone attempted to force this to break without a loud backlash. I think if(ptr) is mostly universally understood to mean the pointer is not null.[...] Since the accuracy of my memory was questioned, I went back to look at the code in question, and indeed I did misremember it, but it was not with arrays, it was with casting pointers to bool. And it was in a while-condition, not an if-condition. Here's a simplified version of the original code: struct Op {...} Op* getOp(...) { ... } ... Op* op; while (!input.empty && cast(bool)(op = getOp(...))) { ... } The cast(bool) used to be accepted up to a certain version (it was in the code from when I first wrote it around 2012), then around 2013 it became a compile error, which forced me to rewrite it as: struct Op {...} Op* getOp(...) { ... } ... Op* op; while (!input.empty && (op = getOp(...)) !is null) { ... } which is much more readable and documents intent more clearly. I originally wrote the cast(bool) because without it the compiler rejects using assignment in an while-condition. I suppose the reasoning is that it's too easy to mistakenly write `while (a=b)` instead of `while (a==b)`. In modern C compilers, an extra set of parentheses usually silenced the compiler warning about a possible typo of ==, but in D even with parentheses the compiler would reject it. So all things considering, this little anecdote represents the following progression in readability (the first 2 steps are hypothetical, since they're only permitted in C): while (a = b) ... // in C, error-prone, could be typo while ((a = b)) ... // still in C, marginally better while (cast(bool)(a = b)) // early D, the conversion is now explicit while ((a = b) !is null) // present-day D, finally intent is clear T -- By understanding a machine-oriented language, the programmer will tend to use a much more efficient method; it is much closer to reality. -- D. Knuth
May 11 2017