Michel Fortin wrote:
On 2009-10-07 17:53:21 -0400, Craig Black <cbl...@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

Reply via email to