Eliminate class allocators and deallocators?

Chris Nicholson-Sauls ibisbasenji at gmail.com
Thu Oct 8 02:00:03 PDT 2009


Michel Fortin wrote:
> On 2009-10-07 17:53:21 -0400, Craig Black <cblack at ara.com> said:
> 
>>> Yes, recycling is best and I'm considering it. I'm only worried about
>>> the extra cost.
>>>
>>> Andrei
>>
>> No this is a bad idea.  Removing the possibility to delete data will 
>> cause serious problems with heap fragmentation in some programs.
> 
> Hum, perhaps we need to review more thoroughly how memory allocation 
> works. As Andrei said himself, we now have all the necessary parts in 
> the language to reimplement 'new' as a library function.
> 
> So let's say we ditch 'new' and 'delete' as keywords. Let's first 
> replace the keyword 'new' with a static function of the same name in a 
> class or a struct. It could be implemented this way:
> 
>     static T new(A...)(A a) {
>         T t = GC.alloc!T(); // GC.alloc sets the T.init bits.
>         t.__ctor(a);
>         return t;
>     }
> 
> Usage:
> 
>     Foo foo = Foo.new();
> 
> That's a static function template that needs to be reimplemented for 
> every subclass (Andrei already proposed such kind of mixins) and that 
> returns a garbage-collected object reference. Now, if you want manual 
> allocation:
> 
>     static T new(A...)(A a) {
>         T t = GC.allocNoCollect!T(); // GC won't collect this bit.
>         t.__ctor(a);
>         return t;
>     }
> 
>     void dispose() {
>         this.__dtor();
>         GC.free(this);
>     }
> 
> Usage:
> 
>     Foo foo = Foo.new();
>     ...
>     foo.dispose();
> 
> But then you could do much better: 'new' could return a different type: 
> a smart reference-counted pointer struct for instance. The possibilities 
> are endless.
> 

Prior to this post I'd been on the side of retaining "good ole" delete, owing somewhat to 
my own tendency to do Evil Things with overloaded new/delete, such as transparent 
free-lists.

I've become neutral in light of the above proposed technique, because it really doesn't 
break that kind of usage.  In fact, it technically makes it more reliable and more 
flexible since the behavior of these is more predictable (not subject to compiler 
quality/method-of-implementation, and guaranteed to be "just another function").

That said, the stdlib (or probably druntime) needs to provide good general-case support 
for this, which should include some sort of IDisposable interface (as mentioned repeatedly 
by others) otherwise we're jumping into the abyss (of massive repetitive coding) rather 
than over it (into the Elysian fields).

One consideration is that new(), perhaps, ought not be a static member of its class at 
all, but rather a global written along similar lines to tools such as "to".  Given that, 
one could write something like:

##################################################
class C {...}

C new (T:C, A...) (A a) {
     auto c = GC.alloc!T();
     c.__ctor(a);
     return c;
}

auto somevar = new! C (1, 2, 3);

// free-listed
class F {...}

F new (T:F, A...) (A a) {
     return F.List.length != 0
         ? F.List.pop
         : defaultNew! F (a)
     ;
}
##################################################

The latter examples shows my thinking: that the stdlib/druntime could easily provide a 
default new() that does what the current new operator does.  Class designers could then 
overload this default new() as needed.  Provide a reasonable alias for the standard new() 
(I used "defaultNew" above, but its probably not the best) and it can still be used as 
backup in custom functions, such as in the free-list example.

Incidentally... does anyone else notice that, in the static-new proposal, we've once again 
recreated Ruby?

Proposed D2:
auto foo = Foo.new;

Ruby:
foo = Foo.new

At least mine looks more like current syntax:
auto foo = new! Foo;

-- Christopher Nicholson-Sauls



More information about the Digitalmars-d mailing list