www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - clear()

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I'm talking with Sean and Walter about taking the first step towards 
eliminating delete: defining function clear() that clears the state of 
an object. Let me know of what you think.

One problem I encountered is that I can't distinguish between a default 
constructor that doesn't need to exist, and one that was disabled 
because of other constructors. Consider:

class A {}
class B { this(int) {} }

You can evaluate "new A" but not "new B". So it's legit to create 
objects of type A all default-initialized. But the pointer to 
constructor stored in A.classinfo is null, same as B.

Any ideas?


Andrei

===============================

void clear(T)(T obj) if (is(T == class))
{
     auto defaultCtor =
         cast(void function(Object)) obj.classinfo.defaultConstructor;
     enforce(defaultCtor);
     immutable size = obj.classinfo.init.length;
     static if (is(typeof(obj.__dtor())))
     {
         obj.__dtor();
     }
     auto buf = (cast(void*) obj)[0 .. size];
     buf[] = obj.classinfo.init;
     defaultCtor(obj);
}

unittest
{
     {
         class A { string s = "A"; this() {} }
         auto a = new A;
         a.s = "asd";
         clear(a);
         assert(a.s == "A");
     }
     {
         static bool destroyed = false;
         class B {
             string s = "B";
             this() {}
             ~this() {
                 destroyed = true;
             }
         }
         auto a = new B;
         a.s = "asd";
         clear(a);
         assert(destroyed);
         assert(a.s == "B");
     }
     {
         class C {
             string s;
             this() {
                 s = "C";
             }
         }
         auto a = new C;
         a.s = "asd";
         clear(a);
         assert(a.s == "C");
     }
}

void clear(T)(ref T obj) if (is(T == struct))
{
     static if (is(typeof(obj.__dtor())))
     {
         obj.__dtor();
     }
     auto buf = (cast(void*) &obj)[0 .. T.sizeof];
     auto init = (cast(void*) &T.init)[0 .. T.sizeof];
     buf[] = init[];
}

unittest
{
     {
         struct A { string s = "A";  }
         A a;
         a.s = "asd";
         clear(a);
         assert(a.s == "A");
     }
     {
         static bool destroyed = false;
         struct B
         {
             string s = "B";
             ~this()
             {
                 destroyed = true;
             }
         }
         B a;
         a.s = "asd";
         clear(a);
         assert(destroyed);
         assert(a.s == "B");
     }
}

void clear(T : U[n], U, size_t n)(/*ref*/ T obj)
{
     obj = T.init;
}

unittest
{
     int[2] a;
     a[0] = 1;
     a[1] = 2;
     clear(a);
     assert(a == [ 0, 0 ]);
}

void clear(T)(ref T obj)
         if (!is(T == struct) && !is(T == class) && !isStaticArray!T)
{
     obj = T.init;
}

unittest
{
     {
         int a = 42;
         clear(a);
         assert(a == 0);
     }
     {
         float a = 42;
         clear(a);
         assert(isnan(a));
     }
}
Oct 09 2009
next sibling parent reply Max Samukha <spambox d-coding.com> writes:
On Fri, 09 Oct 2009 11:40:43 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

I'm talking with Sean and Walter about taking the first step towards 
eliminating delete: defining function clear() that clears the state of 
an object. Let me know of what you think.

One problem I encountered is that I can't distinguish between a default 
constructor that doesn't need to exist, and one that was disabled 
because of other constructors. Consider:

class A {}
class B { this(int) {} }

You can evaluate "new A" but not "new B". So it's legit to create 
objects of type A all default-initialized. But the pointer to 
constructor stored in A.classinfo is null, same as B.

Any ideas?

The notion of default constructor is not quite clear. class A { this(int a = 22) {} } Should A be considered as having a default constructor? class B { this(int) {} } Should passing int.init to B's constructor be considered default construction? If yes, we could recreate B using the init value. But then: class C { this(int a) {} this(int a, int b) {} } Which constructor to call? The one with fewer parameters? What if there are overloaded constructors with identical number of parameters? Should we explicitly mark one of the constructors as default?
Oct 09 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
On 09/10/2009 19:53, Max Samukha wrote:
 On Fri, 09 Oct 2009 11:40:43 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:

 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?

The notion of default constructor is not quite clear. class A { this(int a = 22) {} } Should A be considered as having a default constructor? class B { this(int) {} } Should passing int.init to B's constructor be considered default construction? If yes, we could recreate B using the init value. But then: class C { this(int a) {} this(int a, int b) {} } Which constructor to call? The one with fewer parameters? What if there are overloaded constructors with identical number of parameters? Should we explicitly mark one of the constructors as default?

I agree. classinfo.defaultConstructor should be replaced by an array of all the constructors. Only when the array is empty you assume the existence of the default compiler generated constructor.
Oct 09 2009
parent reply Max Samukha <spambox d-coding.com> writes:
On Fri, 09 Oct 2009 21:50:48 +0200, Yigal Chripun <yigal100 gmail.com>
wrote:

On 09/10/2009 19:53, Max Samukha wrote:
 On Fri, 09 Oct 2009 11:40:43 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:

 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?

The notion of default constructor is not quite clear. class A { this(int a = 22) {} } Should A be considered as having a default constructor? class B { this(int) {} } Should passing int.init to B's constructor be considered default construction? If yes, we could recreate B using the init value. But then: class C { this(int a) {} this(int a, int b) {} } Which constructor to call? The one with fewer parameters? What if there are overloaded constructors with identical number of parameters? Should we explicitly mark one of the constructors as default?

I agree. classinfo.defaultConstructor should be replaced by an array of all the constructors. Only when the array is empty you assume the existence of the default compiler generated constructor.

I'd prefer complete runtime information for all members. The problem is I do not understand what 'default constructor' and 'default construction' means in D for classes that have explicit constructors with parameters. How to automatically construct this cl ass: class B { this(int a = 22) {} } ? For example, Object.factory will always return null for B, which is an arbitrary limitation. class C { this(int a) {} } For C, the "default constructor" should probably be generated like this: void C_ctor(C c) { c.__ctor(int.init); } etc. Otherwise, I cannot see how one can reconstruct an instance of C in 'clear'.
Oct 10 2009
next sibling parent Jacob Carlborg <doob me.com> writes:
On 10/10/09 12:06, Denis Koroskin wrote:
 On Sat, 10 Oct 2009 13:08:01 +0400, Max Samukha <spambox d-coding.com>
 wrote:

 On Fri, 09 Oct 2009 21:50:48 +0200, Yigal Chripun <yigal100 gmail.com>
 wrote:

 On 09/10/2009 19:53, Max Samukha wrote:
 On Fri, 09 Oct 2009 11:40:43 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a
 default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?

The notion of default constructor is not quite clear. class A { this(int a = 22) {} } Should A be considered as having a default constructor? class B { this(int) {} } Should passing int.init to B's constructor be considered default construction? If yes, we could recreate B using the init value. But then: class C { this(int a) {} this(int a, int b) {} } Which constructor to call? The one with fewer parameters? What if there are overloaded constructors with identical number of parameters? Should we explicitly mark one of the constructors as default?

I agree. classinfo.defaultConstructor should be replaced by an array of all the constructors. Only when the array is empty you assume the existence of the default compiler generated constructor.

I'd prefer complete runtime information for all members. The problem is I do not understand what 'default constructor' and 'default construction' means in D for classes that have explicit constructors with parameters. How to automatically construct this cl ass: class B { this(int a = 22) {} } ? For example, Object.factory will always return null for B, which is an arbitrary limitation. class C { this(int a) {} } For C, the "default constructor" should probably be generated like this: void C_ctor(C c) { c.__ctor(int.init); } etc. Otherwise, I cannot see how one can reconstruct an instance of C in 'clear'.

obj.clear(42); Wait, uniform function call syntax doesn't work with classes! Oh, well... clear!(C)(obj, 42);

I've suggested to implement uniform function call syntax: http://d.puremagic.com/issues/show_bug.cgi?id=3382
Oct 10 2009
prev sibling parent Max Samukha <spambox d-coding.com> writes:
On Sat, 10 Oct 2009 14:06:16 +0400, "Denis Koroskin"
<2korden gmail.com> wrote:

obj.clear(42);

Wait, uniform function call syntax doesn't work with classes! Oh, well...

clear!(C)(obj, 42);

We still need polymorphic behavior, meaning all constructors have to be in classinfo, with meta information about parameter types, so that an appropriate constructor can be found. void clear(A...)(Object obj, A args) { ... // find a matching constructor and call it } Object a = new B(41); clear(a, 42);
Oct 10 2009
prev sibling next sibling parent grauzone <none example.net> writes:
Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards 
 eliminating delete: defining function clear() that clears the state of 
 an object. Let me know of what you think.
 
 One problem I encountered is that I can't distinguish between a default 
 constructor that doesn't need to exist, and one that was disabled 
 because of other constructors. Consider:
 
 class A {}
 class B { this(int) {} }
 
 You can evaluate "new A" but not "new B". So it's legit to create 
 objects of type A all default-initialized. But the pointer to 
 constructor stored in A.classinfo is null, same as B.
 
 Any ideas?

You mean for "class A1 { this() {} }", A.classinfo is not null, but for "class A2 {}" it is? Ask Walter to fix it by automatically inserting an empty constructor? Notice that A2 doesn't define __ctor. This would also be a problem for manual allocation. (Although you could work around it with static if(is(...)).) Actually, why don't you just check and call __ctor()? You could add a simple check to see if the dynamic type of the passed object is the same as T (in clear(T)), and raise an error if not. What is clear() supposed to be used for anyway? I still don't understand why it's evil to free the memory block on delete. And now you introduce some clear() function, that basically destroys the object state, even though there still could be live pointers to it that rely on the object having the old state.
Oct 09 2009
prev sibling next sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el  9 de octubre a las 11:40 me escribiste:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state
 of an object. Let me know of what you think.

Bike-shed, but what about the previously suggested name recycle()? I think it make the intention more clear (no pun intended ;) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Far away across the field The tolling of the iron bell Calls the faithful to their knees To hear the softly spoken magic spells.
Oct 09 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Leandro Lucarella wrote:
 Andrei Alexandrescu, el  9 de octubre a las 11:40 me escribiste:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state
 of an object. Let me know of what you think.

Bike-shed, but what about the previously suggested name recycle()? I think it make the intention more clear (no pun intended ;)

Recycle suggested to me that the memory of the object is recycled. Andrei
Oct 09 2009
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-10-09 14:59:20 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Leandro Lucarella wrote:
 Bike-shed, but what about the previously suggested name recycle()? I think
 it make the intention more clear (no pun intended ;)

Recycle suggested to me that the memory of the object is recycled.

'Recycle' is a good term to explain what you intend to do with the object. But I agree with Andrei: 'clear', 'reset' or something alike is much better to explain you're putting the object back in its initial, default, untainted state. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 09 2009
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 10/9/09 18:40, Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?


 Andrei

How about this: static if (is(typeof({ auto t = new T; })))
Oct 09 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jacob Carlborg wrote:
 On 10/9/09 18:40, Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?


 Andrei

How about this: static if (is(typeof({ auto t = new T; })))

I'm in awe. Thanks, Jacob!!! Andrei
Oct 09 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Andrei Alexandrescu wrote:
 Jacob Carlborg wrote:
 On 10/9/09 18:40, Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?


 Andrei

How about this: static if (is(typeof({ auto t = new T; })))

I'm in awe. Thanks, Jacob!!! Andrei

Oh, wait, that doesn't work: class A {} class B : A { this(int) {} } A a = new B; clear(a); // oops Andrei
Oct 09 2009
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-10-09 15:01:30 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 static if (is(typeof({
         auto t = new T;
     })))

I'm in awe. Thanks, Jacob!!! Andrei

Oh, wait, that doesn't work: class A {} class B : A { this(int) {} } A a = new B; clear(a); // oops

It would work, but only as a (virtual) member function redefined for every subclass. Much like a 'clone' method. Sufficient runtime reflection could work too to aleviate that, but it'd execute slower. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 09 2009
prev sibling parent Jason House <jason.james.house gmail.com> writes:
Andrei Alexandrescu Wrote:

 Andrei Alexandrescu wrote:
 Jacob Carlborg wrote:
 On 10/9/09 18:40, Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?


 Andrei

How about this: static if (is(typeof({ auto t = new T; })))

I'm in awe. Thanks, Jacob!!! Andrei

Oh, wait, that doesn't work: class A {} class B : A { this(int) {} } A a = new B; clear(a); // oops Andrei

I did not follow the whole new/delete thread, but I feel like your clear may lead to mixing too many concepts: 1. call destructor for old object 2. placement new for replacement object In general, #1 can break code if extra references are floating around. This isn't as simple as accessing garbage memory or type safety, but also caching of data. For single threaded code, there's two basic issues thatcan pop up: a. Type changes b. Placement new using global references and accidentally accessing itself. For multithreaded code, there are race conditions where external references can be reused. All of this is solved if you have a unique reference... Even the type issue you listed... So, what restrictions should clear impose?
Oct 09 2009
prev sibling parent "Vladimir Panteleev" <thecybershadow gmail.com> writes:
On Fri, 09 Oct 2009 22:01:30 +0300, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Andrei Alexandrescu wrote:
 Jacob Carlborg wrote:
 On 10/9/09 18:40, Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a  
 default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?


 Andrei

How about this: static if (is(typeof({ auto t = new T; })))

Andrei

Oh, wait, that doesn't work: class A {} class B : A { this(int) {} } A a = new B; clear(a); // oops

From what I understand, if you need to be able to look at derived classes, then this information can only be stored in the ClassInfo - but, as you have already pointed out, defaultConstructor is only set for explicit constructors. Therefore you'll need some kind of new flag, which indicates whether the class only has non-default constructors. P.S. I hope that by "eliminating delete" you mean obsoleting it, and not actually taking it out of the language :) -- Best regards, Vladimir mailto:thecybershadow gmail.com
Oct 09 2009
prev sibling next sibling parent grauzone <none example.net> writes:
Andrei Alexandrescu wrote:
 I'm talking with Sean and Walter about taking the first step towards 
 eliminating delete: defining function clear() that clears the state of 
 an object. Let me know of what you think.
 
 One problem I encountered is that I can't distinguish between a default 
 constructor that doesn't need to exist, and one that was disabled 
 because of other constructors. Consider:
 
 class A {}
 class B { this(int) {} }
 
 You can evaluate "new A" but not "new B". So it's legit to create 
 objects of type A all default-initialized. But the pointer to 
 constructor stored in A.classinfo is null, same as B.
 
 Any ideas?

So, after wondering why Object.factory() can instantiate objects even if these objects have no constructor, I read the Phobos documentation (I mean... I read the source, it wasn't in the docs), I found this: uint flags; // 1: // is IUnknown or is derived from IUnknown // 2: // has no possible pointers into GC memory // 4: // has offTi[] member // 8: // has constructors // 16: // has xgetMembers member // 32: // has typeinfo member Yes, flag 8 is exactly what you want.
Oct 09 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sat, 10 Oct 2009 13:08:01 +0400, Max Samukha <spambox d-coding.com>  
wrote:

 On Fri, 09 Oct 2009 21:50:48 +0200, Yigal Chripun <yigal100 gmail.com>
 wrote:

 On 09/10/2009 19:53, Max Samukha wrote:
 On Fri, 09 Oct 2009 11:40:43 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:

 I'm talking with Sean and Walter about taking the first step towards
 eliminating delete: defining function clear() that clears the state of
 an object. Let me know of what you think.

 One problem I encountered is that I can't distinguish between a  
 default
 constructor that doesn't need to exist, and one that was disabled
 because of other constructors. Consider:

 class A {}
 class B { this(int) {} }

 You can evaluate "new A" but not "new B". So it's legit to create
 objects of type A all default-initialized. But the pointer to
 constructor stored in A.classinfo is null, same as B.

 Any ideas?

The notion of default constructor is not quite clear. class A { this(int a = 22) {} } Should A be considered as having a default constructor? class B { this(int) {} } Should passing int.init to B's constructor be considered default construction? If yes, we could recreate B using the init value. But then: class C { this(int a) {} this(int a, int b) {} } Which constructor to call? The one with fewer parameters? What if there are overloaded constructors with identical number of parameters? Should we explicitly mark one of the constructors as default?

I agree. classinfo.defaultConstructor should be replaced by an array of all the constructors. Only when the array is empty you assume the existence of the default compiler generated constructor.

I'd prefer complete runtime information for all members. The problem is I do not understand what 'default constructor' and 'default construction' means in D for classes that have explicit constructors with parameters. How to automatically construct this cl ass: class B { this(int a = 22) {} } ? For example, Object.factory will always return null for B, which is an arbitrary limitation. class C { this(int a) {} } For C, the "default constructor" should probably be generated like this: void C_ctor(C c) { c.__ctor(int.init); } etc. Otherwise, I cannot see how one can reconstruct an instance of C in 'clear'.

obj.clear(42); Wait, uniform function call syntax doesn't work with classes! Oh, well... clear!(C)(obj, 42);
Oct 10 2009