www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - clear() causes crash?

reply =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
This crashes in the last line of main:

     class A
     {
         void foo() {}
     }

     void main()
     {
         A a = new A();
         a.foo();
         clear(a);
         assert(a !is null);
         a.foo();  // crashes
     }

As far as I understand from TDPL book, this should not crash, but 
it does (DMD64 v2.062, OS X). Am I misunderstanding clear()?

BTW, why not make clear also change 'a' to null?
Apr 29 2013
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, April 29, 2013 23:04:29 =?UTF-8?B?Ikx1w61z?=.Marques 
<luismarques gmail.com> puremagic.com wrote:
 This crashes in the last line of main:
 
 class A
 {
 void foo() {}
 }
 
 void main()
 {
 A a = new A();
 a.foo();
 clear(a);
 assert(a !is null);
 a.foo(); // crashes
 }
 
 As far as I understand from TDPL book, this should not crash, but
 it does (DMD64 v2.062, OS X). Am I misunderstanding clear()?
 
 BTW, why not make clear also change 'a' to null?

I think that what TDPL says about clear may be outdated (I don't recall exactly what it said). But clear destroys the class object and zeroes out the vtbl, and it's invalid to do anything with the object after that. It's purely for cases where you want to destroy the object without waiting for the GC to do it (but it doesn't free any memory, so it's pretty much only of use for making sure that the destructor/finalizer gets run). It's very much on purpose that the app crashes when you use an object which you called clear on. Also, clear has been renamed to destroy (leaving clear as an alias to destroy), so new code should be using destroy. - Jonathan M Davis
Apr 29 2013
prev sibling next sibling parent =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Monday, 29 April 2013 at 21:58:46 UTC, Jonathan M Davis wrote:
 zeroes out the vtbl

Hmm, I was expecting that DMD, at least in -release mode, optimize foo() to a direct call, since there's no inheritance.
Apr 30 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Tuesday, 30 April 2013 at 18:54:45 UTC, Luís Marques wrote:
 On Monday, 29 April 2013 at 21:58:46 UTC, Jonathan M Davis 
 wrote:
 zeroes out the vtbl

Hmm, I was expecting that DMD, at least in -release mode, optimize foo() to a direct call, since there's no inheritance.

It was discussed a lot of times in this newsgroup, you can google it quite easily. To sum up: it really can't, unless it is marked as final.
Apr 30 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, April 30, 2013 20:59:17 Dicebot wrote:
 On Tuesday, 30 April 2013 at 18:54:45 UTC, Luís Marques wrote:
 On Monday, 29 April 2013 at 21:58:46 UTC, Jonathan M Davis
 
 wrote:
 zeroes out the vtbl

Hmm, I was expecting that DMD, at least in -release mode, optimize foo() to a direct call, since there's no inheritance.

It was discussed a lot of times in this newsgroup, you can google it quite easily. To sum up: it really can't, unless it is marked as final.

It pretty much comes down to the fact that the compiler can't possibly know that there's no inheritance, because it doesn't have the whole list of classes in the program and _can't_ have the whole list of classes (especially once shared libraries enter the mix). - Jonathan M Davis
Apr 30 2013
prev sibling next sibling parent "Mafi" <mafi example.org> writes:
On Monday, 29 April 2013 at 21:04:30 UTC, Luís Marques wrote:
 This crashes in the last line of main:

     class A
     {
         void foo() {}
     }

     void main()
     {
         A a = new A();
         a.foo();
         clear(a);
         assert(a !is null);
         a.foo();  // crashes
     }

 As far as I understand from TDPL book, this should not crash, 
 but it does (DMD64 v2.062, OS X). Am I misunderstanding clear()?

 BTW, why not make clear also change 'a' to null?

Hasn't 'clear' been renamed to 'destroy'?
Apr 30 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, April 30, 2013 21:47:43 Mafi wrote:
 Hasn't 'clear' been renamed to 'destroy'?

Yes, but an alias to clear still exists, and TDPL talks about clear, not destroy, so anyone reading TDPL would still expect it to be clear. - Jonathan M Davis
Apr 30 2013
prev sibling next sibling parent Denis Shelomovskij <verylonglogin.reg gmail.com> writes:
30.04.2013 1:04, "Luís Marques" <luismarques gmail.com>" пишет:
 This crashes in the last line of main:

      class A
      {
          void foo() {}
      }

      void main()
      {
          A a = new A();
          a.foo();
          clear(a);
          assert(a !is null);
          a.foo();  // crashes
      }

 As far as I understand from TDPL book, this should not crash, but it
 does (DMD64 v2.062, OS X). Am I misunderstanding clear()?

 BTW, why not make clear also change 'a' to null?

Ideally is should throw with pretty message but it isn't implemented. See Issue 8139 - Make objects really disposable by addition of "Object finalized" assertion [1]. IMO, also `destroy` (renamed `clear`) looks like the worst mistake in D runtime and I'd recommend to not use it (or better recompile druntime+phobos without it for your own use). See Issue 9139 - `destroy` is dangerous and inconsistent [2]. Use `unstd.lifetime.finalizeClassInstance` [3] and friends for user-defined lifetime implementation to avoid serious problems. [1] http://d.puremagic.com/issues/show_bug.cgi?id=8139 [2] http://d.puremagic.com/issues/show_bug.cgi?id=9139 [3] http://denis-sh.github.io/phobos-additions/unstd.lifetime.html#finalizeClassInstance -- Денис В. Шеломовский Denis V. Shelomovskij
May 10 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 10 May 2013 22:37:43 -0400, Denis Shelomovskij  =

<verylonglogin.reg gmail.com> wrote:

 30.04.2013 1:04, "Lu=C3=ADs Marques" <luismarques gmail.com>" =D0=BF=D0=

 This crashes in the last line of main:

      class A
      {
          void foo() {}
      }

      void main()
      {
          A a =3D new A();
          a.foo();
          clear(a);
          assert(a !is null);
          a.foo();  // crashes
      }

 As far as I understand from TDPL book, this should not crash, but it
 does (DMD64 v2.062, OS X). Am I misunderstanding clear()?


TDPL states that the object is required to be in a valid state. This = necessarily requires calling a constructor on an object, as an object ha= s = no valid initial state. There are major issues with that requirement, though: 1. How to call a ctor for an object that does not have a default ctor? = In = other words, it requires valid ctor parameters, which the runtime cannot= = possibly know. 2. What if the ctor adds the class instance to a global or some other = rooted memory item? That is, what if the entire point of clearing it is= = so it was not pointed to as being allocated, so the GC would remove it. So the decision was made (correctly) to simply make any object that was = = destroyed be an invalid object. structs will return to their .init valu= e = (which may also be invalid depending on the struct).
 BTW, why not make clear also change 'a' to null?


That could also be done, but it is superficial: auto b =3D a; destroy(a); b.foo(); The only valid thing to do with a after destroying it is to stop using i= t, = and all other references to that instance.
 Ideally is should throw with pretty message but it isn't implemented. =

 See Issue 8139 - Make objects really disposable by addition of "Object=

 finalized" assertion [1].

 IMO, also `destroy` (renamed `clear`) looks like the worst mistake in =

 runtime and I'd recommend to not use it (or better recompile  =

 druntime+phobos without it for your own use). See Issue 9139 - `destro=

 is dangerous and inconsistent [2]. Use  =

 `unstd.lifetime.finalizeClassInstance` [3] and friends for user-define=

 lifetime implementation to avoid serious problems.

 [1] http://d.puremagic.com/issues/show_bug.cgi?id=3D8139
 [2] http://d.puremagic.com/issues/show_bug.cgi?id=3D9139
 [3]  =

 http://denis-sh.github.io/phobos-additions/unstd.lifetime.html#finaliz=


I'm curious why you think it is bad. All you have said here is that it = is = bad, not why. Even bug 9139 says "look at how horrible this is" but = doesn't explain why. The point of destroy is to call destructors without deallocation. The = original charter said to leave the object in a default state, but that = requires re-calling the constructor. In the latest iteration, it simply calls the finalize function in the = runtime. you are not supposed to use it after calling destroy. Not being defensive, I simply don't understand the objection. -Steve
May 13 2013