Dmitry Olshansky wrote:
On 21.07.2010 16:26, bearophile wrote:
Dmitry Olshansky:
The problem is designing such classes and then documenting: "you should
always use it as 'scope' ", is awkward.
If you really want a class to be used as scope only you can do this, see the error message:

scope class Foo {}
void main() {
   Foo f = new Foo;
}


The second writefln prints garbage. I guess it's because of pointer to
the long gone stackframe, which is ovewritten by the first writeln.
Yes scope has this and other problems (and I think two of them can be fixed), but I don't think emplace() is a big improvement.

Bye,
bearophile
Going further with library implementation as opposed to language feature, I made a (somewhat) successful try at implementing scoped classes:

struct Scoped(T){
    ubyte[__traits(classInstanceSize, Test)] _payload;
    T getPayload(){
        return cast(T)(_payload.ptr);
    }
    alias getPayload this;
static Scoped opCall(Args...)(Args args) if ( is(typeof(T.init.__ctor(args))) ){// TODO: should also provide decent error message
        Scoped!T s;
        emplace!T(cast(void[])s._payload,args);
        return s;
    }
    ~this(){
        clear(getPayload);
    }
}

now replace the orignal while loop with this:
while (i < N) {
        auto testObject = Scoped!Test(i, i, i, i, i, i);
//assuming we have aforementioned evil function func(Test t), that keeps global reference to t. //fun(testObject); //uncoment to get an compile error - type mismatch
        testObject.doSomething(i, i, i, i, i, i);
        testObject.doSomething(i, i, i, i, i, i);
        testObject.doSomething(i, i, i, i, i, i);
        testObject.doSomething(i, i, i, i, i, i);
        i++;
    }

and all works just the same as with deprecated scope storage class.
Even better it disallows passing the variable to functions expecting vanilla Test, it's limiting but for a good reason. There are still issues that should be solved (name clash for one, plus the ability to define default construct Scoped!T) but overall it's OK to me.


Nice work. To avoid name clashes with alias this, you may want to use a
trick invented by Shin Fujishiro:

struct ExWhyZee {
   template ExWhyZee() {
      // implementation goes here
   }
   alias ExWhyZee!().whatever this;
}

This way you never have a confusion between the symbols defined by the
wrapped type and your own type. I use a variant of the same trick in
RefCounted.


Andrei

Reply via email to