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









ketmar <ketmar ketmar.no-ip.org> 