www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - static weirdness

reply Alex <sascha.orlov gmail.com> writes:
the story of
https://forum.dlang.org/thread/qknxjxzbaowmsjdngvli forum.dlang.org
continues

How can this be?

void main()
{
     auto s = S();
     auto t = T!s();
     assert(typeof(t).dummy == null);
     assert(t.dummy == null);
     t.foo;

}

struct S
{
     auto fun()
     {
     	return 42;
     }
}

struct T(alias stats)
{
     static typeof(stats)* dummy; // line 21
     static auto foo()
     {
     	assert(dummy == null); // line 24
         assert(dummy.fun == 42); //line 25
     }
}

I thought, if I don't initialize a pointer, like the one in line 
21 (I assert this by the check in line 24) I can't use it line 
line 25.
However, I can...
Jan 23
next sibling parent Alex <sascha.orlov gmail.com> writes:
On Wednesday, 24 January 2018 at 01:48:45 UTC, Alex wrote:

Ah... I figured it out.
For using the function of S, an object does not have to exist...
And in case I would return a member from S, there is a 
segmentation violation, as expected.
So, everything is ok.

Sorry for noise.
Jan 23
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, January 24, 2018 01:48:45 Alex via Digitalmars-d-learn wrote:
 the story of
 https://forum.dlang.org/thread/qknxjxzbaowmsjdngvli forum.dlang.org
 continues

 How can this be?

 void main()
 {
      auto s = S();
      auto t = T!s();
      assert(typeof(t).dummy == null);
      assert(t.dummy == null);
      t.foo;

 }

 struct S
 {
      auto fun()
      {
       return 42;
      }
 }

 struct T(alias stats)
 {
      static typeof(stats)* dummy; // line 21
      static auto foo()
      {
       assert(dummy == null); // line 24
          assert(dummy.fun == 42); //line 25
      }
 }

 I thought, if I don't initialize a pointer, like the one in line
 21 (I assert this by the check in line 24) I can't use it line
 line 25.
 However, I can...
That has nothing to do with static. That has to do with the fact that S.fun is non-virtual (so there's no need to dereference the pointer to call it), and fun doesn't access any members, so it doesn't need to dereference the this pointer internally either. And since the pointer is never dereferenced, it doesn't matter that it's null. You'd get the same behavior if you used a non-static S. On a side note, if you're checking for null, it's better to use the is operator rather than ==. For strings, there's a semantic difference, so it really matters. For classes, it avoids calling the free function opEquals (which will give the same result, but it's a pointless function call when you could just use is and avoid the call). For pointers, it matters that much less, but since it does matter in the other cases (especially strings), it's a good habit to get into just using is null instead of == null. - Jonathan M Davis
Jan 23
next sibling parent Alex <sascha.orlov gmail.com> writes:
On Wednesday, 24 January 2018 at 02:01:54 UTC, Jonathan M Davis 
wrote:
 On Wednesday, January 24, 2018 01:48:45 Alex via 
 Digitalmars-d-learn wrote:
 the story of 
 https://forum.dlang.org/thread/qknxjxzbaowmsjdngvli forum.dlang.org continues

 How can this be?

 void main()
 {
      auto s = S();
      auto t = T!s();
      assert(typeof(t).dummy == null);
      assert(t.dummy == null);
      t.foo;

 }

 struct S
 {
      auto fun()
      {
       return 42;
      }
 }

 struct T(alias stats)
 {
      static typeof(stats)* dummy; // line 21
      static auto foo()
      {
       assert(dummy == null); // line 24
          assert(dummy.fun == 42); //line 25
      }
 }

 I thought, if I don't initialize a pointer, like the one in 
 line
 21 (I assert this by the check in line 24) I can't use it line
 line 25.
 However, I can...
That has nothing to do with static. That has to do with the fact that S.fun is non-virtual (so there's no need to dereference the pointer to call it), and fun doesn't access any members, so it doesn't need to dereference the this pointer internally either. And since the pointer is never dereferenced, it doesn't matter that it's null.
That's cool, by the way :)
 You'd get the same behavior if you used
 a non-static S.

 On a side note, if you're checking for null, it's better to use 
 the is operator rather than ==. For strings, there's a semantic 
 difference, so it really matters. For classes, it avoids 
 calling the free function opEquals (which will give the same 
 result, but it's a pointless function call when you could just 
 use is and avoid the call). For pointers, it matters that much 
 less, but since it does matter in the other cases (especially 
 strings), it's a good habit to get into just using is null 
 instead of == null.
Thanks.
Jan 23
prev sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 24 January 2018 at 02:01:54 UTC, Jonathan M Davis 
wrote:
 (so there's no need to dereference the pointer to call it)
It used to check this pointer with an assert. When did it change?
Jan 25
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, January 25, 2018 10:17:34 Kagamin via Digitalmars-d-learn 
wrote:
 On Wednesday, 24 January 2018 at 02:01:54 UTC, Jonathan M Davis

 wrote:
 (so there's no need to dereference the pointer to call it)
It used to check this pointer with an assert. When did it change?
Actually, assert on a pointer to a struct or a reference to a class checks for null _and_ calls the invariant, and that hasn't changed. But you have to actually assert the pointer or reference if you want to do that, and the OP didn't do that. He asserted whether it == null. - Jonathan M Davis
Jan 25
next sibling parent Alex <sascha.orlov gmail.com> writes:
On Thursday, 25 January 2018 at 12:06:07 UTC, Jonathan M Davis 
wrote:
 On Thursday, January 25, 2018 10:17:34 Kagamin via 
 Digitalmars-d-learn wrote:
 On Wednesday, 24 January 2018 at 02:01:54 UTC, Jonathan M Davis

 wrote:
 (so there's no need to dereference the pointer to call it)
It used to check this pointer with an assert. When did it change?
Actually, assert on a pointer to a struct or a reference to a class checks for null _and_ calls the invariant, and that hasn't changed. But you have to actually assert the pointer or reference if you want to do that, and the OP didn't do that. He asserted whether it == null. - Jonathan M Davis
Yeah... the cool thing is, that if the function does not need anything from the referenced object, then the pointer "degenerates" to a "namespace" implicitly... sorry, for strange wording. It seems that this behavior changed from 2.076.1 to 2.077.
Jan 25
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
On Thursday, 25 January 2018 at 12:06:07 UTC, Jonathan M Davis 
wrote:
 Actually, assert on a pointer to a struct or a reference to a 
 class checks for null _and_ calls the invariant, and that 
 hasn't changed. But you have to actually assert the pointer or 
 reference if you want to do that, and the OP didn't do that. He 
 asserted whether it == null.
I mean the compiler implicitly inserted a check like: struct S { auto fun() { assert(&this!=null); return 42; } }
Jan 25
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, January 25, 2018 12:38:25 Kagamin via Digitalmars-d-learn 
wrote:
 On Thursday, 25 January 2018 at 12:06:07 UTC, Jonathan M Davis

 wrote:
 Actually, assert on a pointer to a struct or a reference to a
 class checks for null _and_ calls the invariant, and that
 hasn't changed. But you have to actually assert the pointer or
 reference if you want to do that, and the OP didn't do that. He
 asserted whether it == null.
I mean the compiler implicitly inserted a check like: struct S { auto fun() { assert(&this!=null); return 42; } }
AFAIK, it has never done that. Walter's stance on null pointers has always been that that's what segfaults are for, and he's against adding any additional null checks. - Jonathan M Davis
Jan 25
prev sibling parent reply Kagamin <spam here.lot> writes:
See https://ideone.com/VZ97dh
Jan 25
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, January 25, 2018 12:42:57 Kagamin via Digitalmars-d-learn 
wrote:
 See https://ideone.com/VZ97dh
I don't know what's going on there. Such an assertion does not seem in line with what Walter has typically said on the subject. Thinking about it, I do vaguely recall a discussion sometime last year about an invariant being invisibly inserted under some set of circumstances. Maybe that's what's happening? I believe that it was complained about in that discussion, so maybe it was removed after that. Certainly, if I try that code locally with master, it runs just fine without hitting any assertions. - Jonathan M Davis
Jan 25
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 25 January 2018 at 12:58:12 UTC, Jonathan M Davis 
wrote:

 Thinking about it, I do vaguely recall a discussion sometime 
 last year about an invariant being invisibly inserted under 
 some set of circumstances. Maybe that's what's happening? I 
 believe that it was complained about in that discussion, so 
 maybe it was removed after that. Certainly, if I try that code 
 locally with master, it runs just fine without hitting any 
 assertions.
https://dlang.org/changelog/2.077.0.html#removePreludeAssert
Jan 25
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/25/18 8:24 AM, Mike Parker wrote:
 On Thursday, 25 January 2018 at 12:58:12 UTC, Jonathan M Davis wrote:
 
 Thinking about it, I do vaguely recall a discussion sometime last year 
 about an invariant being invisibly inserted under some set of 
 circumstances. Maybe that's what's happening? I believe that it was 
 complained about in that discussion, so maybe it was removed after 
 that. Certainly, if I try that code locally with master, it runs just 
 fine without hitting any assertions.
https://dlang.org/changelog/2.077.0.html#removePreludeAssert
I think that changelog is wrong. The prelude assert was added I think to all member calls. And it has been removed. -Steve
Jan 25
prev sibling parent Alex <sascha.orlov gmail.com> writes:
On Thursday, 25 January 2018 at 10:17:34 UTC, Kagamin wrote:
 On Wednesday, 24 January 2018 at 02:01:54 UTC, Jonathan M Davis 
 wrote:
 (so there's no need to dereference the pointer to call it)
It used to check this pointer with an assert. When did it change?
Fortunately, I have some compilers here and just tested it. 2.076.1 results in a segmentation fault, whereas 2.077.0 does not.
Jan 25