digitalmars.D - null this, classes, methods and "null this" assertion
- ketmar (36/36) Apr 10 2015 let's take a code like this:
- Steven Schveighoffer (4/18) Apr 10 2015 In non-release mode, it's calling the invariant, which is a virtual
- ketmar (3/27) Apr 10 2015 yet compiler can generate `CondExp` instead of `AssertExp`, and don't=20
- Steven Schveighoffer (5/10) Apr 10 2015 A virtual function cannot be called on a null pointer. I would have
- ketmar (26/39) Apr 10 2015 it does literally this:
- Meta (3/50) Apr 10 2015 As an aside, you could easily make length a UFCS function that
- ketmar (3/5) Apr 10 2015 sure i can workaround the check. but this makes my code messier, as some...
let's take a code like this: import std.stdio; class A { size_t len =3D 42; final size_t length () const { return (this !is null ? len : 0); } } void main () { A a; writeln(a.length); a =3D new A(); writeln(a.length); } in "-release" mode this code outputs "0" and "42", as expected (by me). but without "-release" is raises "null this" assertion. while such check *may* be useful, it actually does nothing at all for=20 virtual functions (if we'll remove `final` from `length`, we'll get=20 segfault), and prevents writing non-virtual functions that can do=20 something sane for "null objects". my example with `length` actually has sense, as it mimicking the built-in=20 array behavior. instead of writing if (obj !is null && obj.length > 0) i can simply write: if (obj.length > 0) yet there is no way to tell the compiler (and this assert is generated by=20 the compiler) to not generate the assert for given method. i see that assert as completely unnecessary: 1. it does nothing to protect me from calling virtual method with null=20 object. 2. it forces me to write unnecessary null checks everywhere in my code=20 instead of delegating that to class methods. we can add another attribute that turns off such checks, but i'm=20 proposing to remove that check altogether, cause: 1. there are too many attributes already. 2. let non-virtual methods segfaults as virtual ones already does, thus=20 making 'em consistent. please, kill that counter-productive limiting "feature" for good!=
Apr 10 2015
On 4/10/15 9:59 PM, ketmar wrote:let's take a code like this: import std.stdio; class A { size_t len = 42; final size_t length () const { return (this !is null ? len : 0); } } void main () { A a; writeln(a.length); a = new A(); writeln(a.length); } in "-release" mode this code outputs "0" and "42", as expected (by me). but without "-release" is raises "null this" assertion.In non-release mode, it's calling the invariant, which is a virtual function. -Steve
Apr 10 2015
On Fri, 10 Apr 2015 22:06:53 -0400, Steven Schveighoffer wrote:On 4/10/15 9:59 PM, ketmar wrote:yet compiler can generate `CondExp` instead of `AssertExp`, and don't=20 fail when `this` is `null`.=let's take a code like this: import std.stdio; class A { size_t len =3D 42; final size_t length () const { return (this !is null ? len : 0); } } void main () { A a; writeln(a.length); a =3D new A(); writeln(a.length); } in "-release" mode this code outputs "0" and "42", as expected (by me). but without "-release" is raises "null this" assertion.=20 In non-release mode, it's calling the invariant, which is a virtual function. =20 -Steve
Apr 10 2015
On 4/10/15 10:17 PM, ketmar wrote:On Fri, 10 Apr 2015 22:06:53 -0400, Steven Schveighoffer wrote:A virtual function cannot be called on a null pointer. I would have actually expected it to crash, but maybe it does something special for invariant. -SteveIn non-release mode, it's calling the invariant, which is a virtual function.yet compiler can generate `CondExp` instead of `AssertExp`, and don't fail when `this` is `null`.
Apr 10 2015
On Fri, 10 Apr 2015 22:49:07 -0400, Steven Schveighoffer wrote:On 4/10/15 10:17 PM, ketmar wrote:it does literally this: Expression *v =3D new ThisExp(Loc()); v->type =3D vthis->type; if (ad->isStructDeclaration()) v =3D v->addressOf(); Expression *se =3D new StringExp(Loc(), (char *)"null this"); se =3D se->semantic(sc); se->type =3D Type::tchar->arrayOf(); e =3D new AssertExp(Loc(), v, se); what i suggest is to change `AssertExp` to `CondExp` (when=20 global.params.useAssert and global.params.useInvariants are both set). it=20 *should* do the same, i think. i.e. do something like this: if (global.params.useAssert && global.params.useInvariants) { Expression *v =3D new ThisExp(Loc()); v->type =3D vthis->type; if (ad->isStructDeclaration()) v =3D v->addressOf(); e =3D new CondExp(Loc(), v, v->syntaxCopy(), new NullExp(Loc())); } else { e =3D new HaltExp(Loc()); } e =3D e->semantic(sc); e->type =3D Type::tvoid; dunno if `syntaxCopy` is necessary here, though, and how is it all=20 related to calling invariant function. it's just a blind guess.=On Fri, 10 Apr 2015 22:06:53 -0400, Steven Schveighoffer wrote:A virtual function cannot be called on a null pointer. I would have actually expected it to crash, but maybe it does something special for invariant.In non-release mode, it's calling the invariant, which is a virtual function.yet compiler can generate `CondExp` instead of `AssertExp`, and don't fail when `this` is `null`.
Apr 10 2015
On Saturday, 11 April 2015 at 01:59:28 UTC, ketmar wrote:let's take a code like this: import std.stdio; class A { size_t len = 42; final size_t length () const { return (this !is null ? len : 0); } } void main () { A a; writeln(a.length); a = new A(); writeln(a.length); } in "-release" mode this code outputs "0" and "42", as expected (by me). but without "-release" is raises "null this" assertion. while such check *may* be useful, it actually does nothing at all for virtual functions (if we'll remove `final` from `length`, we'll get segfault), and prevents writing non-virtual functions that can do something sane for "null objects". my example with `length` actually has sense, as it mimicking the built-in array behavior. instead of writing if (obj !is null && obj.length > 0) i can simply write: if (obj.length > 0) yet there is no way to tell the compiler (and this assert is generated by the compiler) to not generate the assert for given method. i see that assert as completely unnecessary: 1. it does nothing to protect me from calling virtual method with null object. 2. it forces me to write unnecessary null checks everywhere in my code instead of delegating that to class methods. we can add another attribute that turns off such checks, but i'm proposing to remove that check altogether, cause: 1. there are too many attributes already. 2. let non-virtual methods segfaults as virtual ones already does, thus making 'em consistent. please, kill that counter-productive limiting "feature" for good!As an aside, you could easily make length a UFCS function that avoids the null check.
Apr 10 2015
On Sat, 11 Apr 2015 02:19:50 +0000, Meta wrote:As an aside, you could easily make length a UFCS function that avoids the null check.sure i can workaround the check. but this makes my code messier, as some=20 class methods are now defined outside the class.=
Apr 10 2015