digitalmars.D - assert(obj) is an atrocity
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (20/20) Nov 08 2011 Hi,
- bearophile (4/5) Nov 08 2011 I tend to agree with this idea.
- Trass3r (1/1) Nov 08 2011 +1
- Timon Gehr (2/16) Nov 08 2011 +1.
- dsimcha (5/24) Nov 08 2011 +1. **AND** in debug mode all pointers should be checked for null.
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (4/29) Nov 08 2011 I agree on that point. Though right now I'd just be happy to have sane
- Kapps (4/29) Nov 08 2011 Agreed. It would be nice to have an error thrown instead of just a
- Martin Nowak (17/37) Nov 08 2011 ne =
- Timon Gehr (4/36) Nov 08 2011 No, he is suggesting to add a null check for assert(objref);, a
- Timon Gehr (2/42) Nov 08 2011 BTW, the number of occurrences of assert(objref && 1); in my code is hug...
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (5/48) Nov 08 2011 Just for the record, someone on the D IRC channel suggested using
- Martin Nowak (17/61) Nov 08 2011 -in
- Timon Gehr (14/72) Nov 08 2011 What exactly do you consider harmful? If a function cannot deal with
- bcs (2/45) Nov 08 2011 I would have used assert(!!obj) because it's shorter.
- Timon Gehr (2/50) Nov 08 2011 If you have already typed 'assert(obj', it is not shorter.
- bcs (4/59) Nov 09 2011 Faster to type? No. Shorter? Yes it still is. I spend enough more time
- Martin Nowak (28/68) Nov 08 2011 in
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (4/67) Nov 09 2011 But as that BUG note states, it still isn't sufficient/consistent. :)
- Jesse Phillips (3/4) Nov 08 2011 http://d.puremagic.com/issues/show_bug.cgi?id=6913
- Daniel Murphy (5/9) Nov 08 2011 This is nearly 5 years old:
- Davidson Corry (8/28) Nov 08 2011 I don't get it -- why is this even necessary? Please don't answer here.
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (4/36) Nov 09 2011 This has nothing to do with learning. This entire thread is a language
- Bernard Helyer (1/1) Nov 09 2011 Because it's a design issue, not a learning issue?
- Dejan Lekic (2/2) Nov 09 2011 Alex, it is a well know bug, I remember it from... ~2006... It has been
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (4/6) Nov 09 2011 Yep, I just figured I'd bring some attention to it again, as well as
- Bernard Helyer (4/4) Nov 09 2011 Agreed on all points. It's pathetic that this is still a problem. Check
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (6/26) Nov 13 2011 I'd just like to add, regarding asserting invariants: Why not just *make...
- Andrej Mitrovic (3/6) Nov 13 2011 I think you would have to wrap it as debug() { obj.invariant(); },
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (3/9) Nov 13 2011 The compiler could easily do that work, however.
- Jonathan M Davis (35/39) Nov 13 2011 Call __invariant. But like all __ functions, I don't think that it's re=
- bearophile (5/11) Nov 13 2011 I didn't remember this about pointer to struct.
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (42/66) Nov 19 2011 I ran into a funny issue today. I wanted to assert that all items in a
- bearophile (4/6) Nov 19 2011 Python Zen says "Explicit is better than implicit.". Calling the invaria...
Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - Alex
Nov 08 2011
Alex R. Petersen:But please, please, *please* check the object for null first.I tend to agree with this idea. Bye, bearophile
Nov 08 2011
On 11/08/2011 11:35 PM, Alex Rønne Petersen wrote:Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first.+1.
Nov 08 2011
On 11/8/2011 7:05 PM, Timon Gehr wrote:On 11/08/2011 11:35 PM, Alex Rønne Petersen wrote:+1. **AND** in debug mode all pointers should be checked for null. Conceptually, I fail to see how a null pointer dereference is different from an array bounds error. A null pointer is effectively an array with length zero.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first.+1.
Nov 08 2011
On 09-11-2011 01:19, dsimcha wrote:On 11/8/2011 7:05 PM, Timon Gehr wrote:I agree on that point. Though right now I'd just be happy to have sane asserts. - AlexOn 11/08/2011 11:35 PM, Alex Rønne Petersen wrote:+1. **AND** in debug mode all pointers should be checked for null. Conceptually, I fail to see how a null pointer dereference is different from an array bounds error. A null pointer is effectively an array with length zero.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first.+1.
Nov 08 2011
Agreed. It would be nice to have an error thrown instead of just a segfault that you may or may not get a reliable backtrace for and then spend the next few days trying to find out where it is. -_- On 08/11/2011 6:19 PM, dsimcha wrote:On 11/8/2011 7:05 PM, Timon Gehr wrote:On 11/08/2011 11:35 PM, Alex Rønne Petersen wrote:+1. **AND** in debug mode all pointers should be checked for null. Conceptually, I fail to see how a null pointer dereference is different from an array bounds error. A null pointer is effectively an array with length zero.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first.+1.
Nov 08 2011
On Tue, 08 Nov 2011 23:35:33 +0100, Alex R=C3=B8nne Petersen = <xtzgzorex gmail.com> wrote:Hi, As the title suggests, I'm going to be rather blunt about this. =assert(obj) testing the invariant *without* doing a null check is insa=ne =for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely =broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in==assert(). 4) The few added instructions for the null check hardly matter in a =*debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that =very much makes sense. But please, please, *please* check the object f=or =null first. This is a random inconsistency in the language with no oth=er =justification than "seg faults are convenient in a debugger". By the =same logic, we might as well not have array bounds checks. However, th=e =state of things is that array bounds checks are emitted by default and==users can disable them for e.g. a release build. I don't see why this ==case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is like= ly compiled without assertions. Are you really suggesting to add a null che= ck = before every method call? martin
Nov 08 2011
On 11/09/2011 01:18 AM, Martin Nowak wrote:On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 08 2011
On 11/09/2011 01:21 AM, Timon Gehr wrote:On 11/09/2011 01:18 AM, Martin Nowak wrote:BTW, the number of occurrences of assert(objref && 1); in my code is huge.On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 08 2011
On 09-11-2011 01:28, Timon Gehr wrote:On 11/09/2011 01:21 AM, Timon Gehr wrote:Just for the record, someone on the D IRC channel suggested using assert(!!obj); as another workaround. Obviously still ugly as hell, but less so. - AlexOn 11/09/2011 01:18 AM, Martin Nowak wrote:BTW, the number of occurrences of assert(objref && 1); in my code is huge.On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 08 2011
On Wed, 09 Nov 2011 01:28:06 +0100, Timon Gehr <timon.gehr gmx.ch> wrote= :On 11/09/2011 01:21 AM, Timon Gehr wrote:-inOn 11/09/2011 01:18 AM, Martin Nowak wrote:On Tue, 08 Nov 2011 23:35:33 +0100, Alex R=C3=B8nne Petersen <xtzgzorex gmail.com> wrote:Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built=assert(). 4) The few added instructions for the null check hardly matter in a=t*debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, tha=tvery much makes sense. But please, please, *please* check the objec=nofor null first. This is a random inconsistency in the language with=Byother justification than "seg faults are convenient in a debugger".=dthe same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitte=by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null=BTW, the number of occurrences of assert(objref && 1); in my code is =check before every method call? martinNo, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.huge.Just as a side note. I personally consider this as harmful. All too often an assert(obj !is = null) is misused as disclaimer. It pretends false safety, while the obscure case where = something is called with null is not found during testing. It also creates a coupling of the caller and the callee, because not = calling something with null is now part of the in contract.
Nov 08 2011
On 11/09/2011 01:46 AM, Martin Nowak wrote:On Wed, 09 Nov 2011 01:28:06 +0100, Timon Gehr <timon.gehr gmx.ch> wrote:What exactly do you consider harmful? If a function cannot deal with null it cannot. I like to have an assertion failure during debugging rather than a segfault. There is no "false safety", or "true safety" for that matter, it is just as safe as not asserting before dereferencing the null pointer. //... this(Class cc)in{assert(cc&&1);}body{c=cc;} invariant(){ assert(c&&1); } void foo(){/* rely on c !is null. */} //... (Btw, I tried to verify my statement, but actually there were only about 30 of those asserts in >6000 LOC.)On 11/09/2011 01:21 AM, Timon Gehr wrote:Just as a side note. I personally consider this as harmful. All too often an assert(obj !is null) is misused as disclaimer. It pretends false safety, while the obscure case where something is called with null is not found during testing.On 11/09/2011 01:18 AM, Martin Nowak wrote:BTW, the number of occurrences of assert(objref && 1); in my code is huge.On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martinIt also creates a coupling of the caller and the callee, because not calling something with null is now part of the in contract.You make it sound like that is a bad thing?
Nov 08 2011
On 11/08/2011 04:28 PM, Timon Gehr wrote:On 11/09/2011 01:21 AM, Timon Gehr wrote:I would have used assert(!!obj) because it's shorter.On 11/09/2011 01:18 AM, Martin Nowak wrote:BTW, the number of occurrences of assert(objref && 1); in my code is huge.On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 08 2011
On 11/09/2011 04:52 AM, bcs wrote:On 11/08/2011 04:28 PM, Timon Gehr wrote:If you have already typed 'assert(obj', it is not shorter.On 11/09/2011 01:21 AM, Timon Gehr wrote:I would have used assert(!!obj) because it's shorter.On 11/09/2011 01:18 AM, Martin Nowak wrote:BTW, the number of occurrences of assert(objref && 1); in my code is huge.On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 08 2011
On 11/08/2011 11:42 PM, Timon Gehr wrote:On 11/09/2011 04:52 AM, bcs wrote:Faster to type? No. Shorter? Yes it still is. I spend enough more time reading and thinking about code that size is more relevant then typing speed.On 11/08/2011 04:28 PM, Timon Gehr wrote:If you have already typed 'assert(obj', it is not shorter.On 11/09/2011 01:21 AM, Timon Gehr wrote:I would have used assert(!!obj) because it's shorter.On 11/09/2011 01:18 AM, Martin Nowak wrote:BTW, the number of occurrences of assert(objref && 1); in my code is huge.On Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 09 2011
On Wed, 09 Nov 2011 01:21:47 +0100, Timon Gehr <timon.gehr gmx.ch> wrote= :On 11/09/2011 01:18 AM, Martin Nowak wrote:inOn Tue, 08 Nov 2011 23:35:33 +0100, Alex R=C3=B8nne Petersen <xtzgzorex gmail.com> wrote:Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-=assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that=very much makes sense. But please, please, *please* check the object=nofor null first. This is a random inconsistency in the language with =Byother justification than "seg faults are convenient in a debugger". =the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted=by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is =likely compiled without assertions. Are you really suggesting to add a null check before every method call? martinNo, he is suggesting to add a null check for assert(objref);, a =construct that *looks* as if it was a null check, but does something =almost unrelated.Then just for reference, apply this patch to druntime and you'll get an = = assertion instead. diff --git a/src/rt/invariant.d b/src/rt/invariant.d index 71337f1..bc5e53a 100644 --- a/src/rt/invariant.d +++ b/src/rt/invariant.d -16,13 +16,16 /** * */ +import core.exception; + void _d_invariant(Object o) { ClassInfo c; //printf("__d_invariant(%p)\n", o); // BUG: needs to be filename/line of caller, not library routine - assert(o !is null); // just do null check, not invariant check + if (o is null) + throw new AssertError("_d_invariant called with null reference.= "); c =3D o.classinfo; do
Nov 08 2011
On 09-11-2011 01:57, Martin Nowak wrote:On Wed, 09 Nov 2011 01:21:47 +0100, Timon Gehr <timon.gehr gmx.ch> wrote:But as that BUG note states, it still isn't sufficient/consistent. :) Thanks for the patch though! - AlexOn 11/09/2011 01:18 AM, Martin Nowak wrote:Then just for reference, apply this patch to druntime and you'll get an assertion instead. diff --git a/src/rt/invariant.d b/src/rt/invariant.d index 71337f1..bc5e53a 100644 --- a/src/rt/invariant.d +++ b/src/rt/invariant.d -16,13 +16,16 /** * */ +import core.exception; + void _d_invariant(Object o) { ClassInfo c; //printf("__d_invariant(%p)\n", o); // BUG: needs to be filename/line of caller, not library routine - assert(o !is null); // just do null check, not invariant check + if (o is null) + throw new AssertError("_d_invariant called with null reference."); c = o.classinfo; doOn Tue, 08 Nov 2011 23:35:33 +0100, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:No, he is suggesting to add a null check for assert(objref);, a construct that *looks* as if it was a null check, but does something almost unrelated.Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexIt does check for null. Only it's a runtime support function (_d_invariant) and druntime is likely compiled without assertions. Are you really suggesting to add a null check before every method call? martin
Nov 09 2011
Alex Rønne Petersen Wrote:Hi,http://d.puremagic.com/issues/show_bug.cgi?id=6913 +1
Nov 08 2011
"Jesse Phillips" <jessekphillips+D gmail.com> wrote in message news:j9cikj$t8a$1 digitalmars.com...Alex Rønne Petersen Wrote:This is nearly 5 years old: http://d.puremagic.com/issues/show_bug.cgi?id=796 And has a patch on github.Hi,http://d.puremagic.com/issues/show_bug.cgi?id=6913 +1
Nov 08 2011
I don't get it -- why is this even necessary? Please don't answer here. Swing over to D.learn, where I am starting an "assert(obj) is a mystery" thread... ...because answers that start with "because..." belong in a "learn" newsgroup. Thanks in advance. -- Davidson On 11/8/2011 2:35 PM, Alex Rønne Petersen wrote:Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - Alex
Nov 08 2011
On 09-11-2011 06:23, Davidson Corry wrote:I don't get it -- why is this even necessary? Please don't answer here. Swing over to D.learn, where I am starting an "assert(obj) is a mystery" thread... ...because answers that start with "because..." belong in a "learn" newsgroup. Thanks in advance. -- Davidson On 11/8/2011 2:35 PM, Alex Rønne Petersen wrote:This has nothing to do with learning. This entire thread is a language design counter-argument. - AlexHi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - Alex
Nov 09 2011
Because it's a design issue, not a learning issue?
Nov 09 2011
Alex, it is a well know bug, I remember it from... ~2006... It has been reported as a bug ages ago... I/we totally agree with you.
Nov 09 2011
On 09-11-2011 12:48, Dejan Lekic wrote:Alex, it is a well know bug, I remember it from... ~2006... It has been reported as a bug ages ago... I/we totally agree with you.Yep, I just figured I'd bring some attention to it again, as well as some arguments for why the way it is now is broken. - Alex
Nov 09 2011
Agreed on all points. It's pathetic that this is still a problem. Check the object for null. To not do so is a _bug_, even if Walter disagrees. SDC will not replicate DMD's behaviour in this regard. -Bernard.
Nov 09 2011
On 08-11-2011 23:35, Alex Rønne Petersen wrote:Hi, As the title suggests, I'm going to be rather blunt about this. assert(obj) testing the invariant *without* doing a null check is insane for the following reasons: 1) It is not what a user expects. It is *unintuitive*. 2) assert(!obj) does an is-null check. assert(obj) is a completely broken opposite of this. 3) No AssertError is thrown, which is the entire point of the built-in assert(). 4) The few added instructions for the null check hardly matter in a *debug* build of all things. I don't mind assert(obj) testing the invariant of obj. In fact, that very much makes sense. But please, please, *please* check the object for null first. This is a random inconsistency in the language with no other justification than "seg faults are convenient in a debugger". By the same logic, we might as well not have array bounds checks. However, the state of things is that array bounds checks are emitted by default and users can disable them for e.g. a release build. I don't see why this case is any different. - AlexI'd just like to add, regarding asserting invariants: Why not just *make invariants callable*? I.e. obj.invariant() invokes the invariant function. invariant is already a keyword, and invariants are declared like functions, so this seems like a logical thing to do. - Alex
Nov 13 2011
On 11/13/11, Alex R=F8nne Petersen <xtzgzorex gmail.com> wrote:I'd just like to add, regarding asserting invariants: Why not just *make invariants callable*? I.e. obj.invariant() invokes the invariant function.I think you would have to wrap it as debug() { obj.invariant(); }, otherwise you would end up calling the invariant in release-mode.
Nov 13 2011
On 13-11-2011 19:43, Andrej Mitrovic wrote:On 11/13/11, Alex Rønne Petersen<xtzgzorex gmail.com> wrote:The compiler could easily do that work, however. - AlexI'd just like to add, regarding asserting invariants: Why not just *make invariants callable*? I.e. obj.invariant() invokes the invariant function.I think you would have to wrap it as debug() { obj.invariant(); }, otherwise you would end up calling the invariant in release-mode.
Nov 13 2011
On Sunday, November 13, 2011 18:52:35 Alex R=C3=B8nne Petersen wrote:I'd just like to add, regarding asserting invariants: Why not just *m=akeinvariants callable*? I.e. obj.invariant() invokes the invariant function. invariant is already a keyword, and invariants are declared=like functions, so this seems like a logical thing to do.Call __invariant. But like all __ functions, I don't think that it's re= ally=20 intended to be called directly in code. You can do it though. Really, I don't think that there's a problem with assert(obj) calling o= bj's=20 invariant. It's just extra overhead in a non-release build which is run= ning a=20 set of assertions which should be true anyway (assuming that it's being= called=20 outside of the class). It's the fact that it doesn't check for null fir= st which=20 is so atrocious, since that _completely_ changes the semantics of what = obj=20 normally does when implicitly converted to bool. If it checked for null= first,=20 then the normal semantics hold with the addition of checking the invari= ant. The fun part about assert(obj) though is that it doesn't work with stru= cts -=20 not directly anyway. If obj is a struct, assert(obj) tries to convert i= t to=20 bool like it would do normally. However, assert(&obj) _does_ call the=20= invariant. Pointers to structs are treated exactly the same as referenc= es to=20 classes in this case (complete with the lack of a null check). So, it's= =20 arguably consistent, but it's a bit weird. In any case, what really needs to be done is to add the extra null chec= k. It=20 won't silently break code to do that, and it'll avoid the surprise and=20= confusiong of assert(obj) not checking for null and blowing up as a res= ult. - Jonathan M Davis
Nov 13 2011
Jonathan M Davis:The fun part about assert(obj) though is that it doesn't work with structs - not directly anyway. If obj is a struct, assert(obj) tries to convert it to bool like it would do normally. However, assert(&obj) _does_ call the invariant. Pointers to structs are treated exactly the same as references to classes in this case (complete with the lack of a null check). So, it's arguably consistent, but it's a bit weird.I didn't remember this about pointer to struct. Generally a good language needs to be designed with a more explicit syntax (unless the operation is very commonly done in this language, or among other languages too). If I am a newbie that doesn't know D a lot, and I see those asserts, for class instances, struct instances, and struct instances with &, I can't tell what they mean. This is not so good. Bye, bearophile
Nov 13 2011
On 13-11-2011 22:38, Jonathan M Davis wrote:On Sunday, November 13, 2011 18:52:35 Alex Rønne Petersen wrote:I ran into a funny issue today. I wanted to assert that all items in a collection are not null. Naturally, I just did something like: invariant() { foreach (item; _store) assert(item); } That was a bad idea, however! Because this assert calls the invariant of item, *it can end up causing an infinite loop*. This can happen in a scenario such as: class A { Collection!B col; invariant() { assert(col); } } class B { A a; invariant() { assert(a); } } auto a = new A(); a.col = new Collection!B(); auto b = new B(); b.a = a; a.col.add(b); assert(b); The call sequence will now look something like: 1: B.invariant() 2: A.invariant() 3: Collection!B.invariant() 4: *B.invariant()* 5: ... and so on ... I just thought it was worth mentioning how calling the invariant in assert can lead to very unexpected results. Of course, the solution is simple: assert(item !is null); in the collection invariant. Still, I think this is just as unintuitive as the missing null check. I think we need to keep it simple here.I'd just like to add, regarding asserting invariants: Why not just *make invariants callable*? I.e. obj.invariant() invokes the invariant function. invariant is already a keyword, and invariants are declared like functions, so this seems like a logical thing to do.Call __invariant. But like all __ functions, I don't think that it's really intended to be called directly in code. You can do it though. Really, I don't think that there's a problem with assert(obj) calling obj's invariant. It's just extra overhead in a non-release build which is running a set of assertions which should be true anyway (assuming that it's being called outside of the class). It's the fact that it doesn't check for null first which is so atrocious, since that _completely_ changes the semantics of what obj normally does when implicitly converted to bool. If it checked for null first, then the normal semantics hold with the addition of checking the invariant.The fun part about assert(obj) though is that it doesn't work with structs - not directly anyway. If obj is a struct, assert(obj) tries to convert it to bool like it would do normally. However, assert(&obj) _does_ call the invariant. Pointers to structs are treated exactly the same as references to classes in this case (complete with the lack of a null check). So, it's arguably consistent, but it's a bit weird. In any case, what really needs to be done is to add the extra null check. It won't silently break code to do that, and it'll avoid the surprise and confusiong of assert(obj) not checking for null and blowing up as a result. - Jonathan M Davis- Alex
Nov 19 2011
Alex R. Petersen:I just thought it was worth mentioning how calling the invariant in assert can lead to very unexpected results.Python Zen says "Explicit is better than implicit.". Calling the invariant with an explicit syntax is better than calling it implicitly with an assert syntax that looks like it does something different. Bye, bearophile
Nov 19 2011