October 05, 2015
On Monday, 5 October 2015 at 20:49:08 UTC, bitwise wrote:
> On Monday, 5 October 2015 at 20:23:41 UTC, Namespace wrote:
>> On Monday, 5 October 2015 at 19:07:20 UTC, Meta wrote:
>>> [...]
>>
>> ----
>> import std.stdio;
>>
>> [...]
>
> I think you kinda missed the point. The second one was _supposed_ to be typed as Foo.
>
> The point is that the compiler allows it. It's unsafe.
>
>    Bit

Ah, right. I've overseen it.
October 05, 2015
But you can simply relinquish alias this and use opDispatch. Problem solved.
October 05, 2015
On Monday, 5 October 2015 at 21:29:20 UTC, Namespace wrote:
> But you can simply relinquish alias this and use opDispatch. Problem solved.

I don't understand what you mean.

Thinking about this now though, shouldn't this be a bug?

I think there should be a rule for this one:

class A{}
struct B { A a; alias a this; }
A a = B();  // error

Error: assignment from alias this not allowed for class or interface alias.

    Bit
October 05, 2015
On Monday, 5 October 2015 at 21:29:20 UTC, Namespace wrote:
> But you can simply relinquish alias this and use opDispatch. Problem solved.

There is std.typecons.Proxy which may do the trick. It provides forwarding while disallowing implicit conversion. It might make sense to reimplement `scoped` in terms of Proxy, I don't know.
October 05, 2015
On Monday, 5 October 2015 at 22:48:37 UTC, Meta wrote:
> On Monday, 5 October 2015 at 21:29:20 UTC, Namespace wrote:
>> But you can simply relinquish alias this and use opDispatch. Problem solved.
>
> There is std.typecons.Proxy which may do the trick. It provides forwarding while disallowing implicit conversion. It might make sense to reimplement `scoped` in terms of Proxy, I don't know.

Well, again that has it's pros and cons. This is why I just want a normal language solution like DIP74.

http://imgur.com/v6CIWln

     Bit

October 06, 2015
On Monday, 5 October 2015 at 23:08:37 UTC, bitwise wrote:
> Well, again that has it's pros and cons. This is why I just want a normal language solution like DIP74.

They're not the same thing at all. scoped is supposed to put the class on the stack, not the heap. And it's not ref-counted. It's so that you can create a class object in place, use it, and throw it away without doing any heap allocation. Essentially, it allows you to use a class as if it were a non-copyable struct. Even if we end up with ref-counting supported in the language, it doesn't obviate the need for scoped classes. They're for different use cases.

- Jonathan M Davis
October 06, 2015
On Monday, 5 October 2015 at 22:15:59 UTC, bitwise wrote:
> On Monday, 5 October 2015 at 21:29:20 UTC, Namespace wrote:
>> But you can simply relinquish alias this and use opDispatch. Problem solved.
>
> I don't understand what you mean.

----
import std.stdio;

struct Scoped(T) {
    private void[__traits(classInstanceSize, T)] buf = void;

    this(Args...)(auto ref Args args) {
        this.buf = typeid(T).init[];
        this.get().__ctor(args);
    }

    ~this() {
        .destroy(this.get());
    }


    private T get() {
        return cast(T) this.buf.ptr;
    }

    auto opDispatch(string method, Args...)(auto ref Args args) {
        return mixin("this.get()." ~ method ~ "(args)");
    }
}

auto scoped(T, Args...)(auto ref Args args) {
    return Scoped!T(args);
}

class A
{
    string name;

    this(string name)
    {
       this.name = name;
       writeln("Creating A");
    }

    ~this()
    {
       writeln("Destroying A");
    }

    void hello()
    {
       writeln("Hello, ", this.name);
    }
}

void main() {
    //A a0 = scoped!A("Test"); <-- fails

    auto a1 = scoped!A("Foo");
    a1.hello();

    auto a2 = scoped!A("Bar");
    a2.hello();
}
----
October 06, 2015
On Tuesday, 6 October 2015 at 06:45:47 UTC, Jonathan M Davis wrote:
> On Monday, 5 October 2015 at 23:08:37 UTC, bitwise wrote:
>> Well, again that has it's pros and cons. This is why I just want a normal language solution like DIP74.
>
> They're not the same thing at all. scoped is supposed to put the class on the stack, not the heap. And it's not ref-counted. It's so that you can create a class object in place, use it, and throw it away without doing any heap allocation. Essentially, it allows you to use a class as if it were a non-copyable struct. Even if we end up with ref-counting supported in the language, it doesn't obviate the need for scoped classes. They're for different use cases.

Why not leave stack allocation of objects to the compiler, like inlining? Then add a "@stack" constraint that will make the compilation fail if the compiler is unable to put it on the stack?

You need the compiler to prove that that the life time of the object is shorter than the stack frame in order to have memory safety anyway.

October 06, 2015
On Tuesday, 6 October 2015 at 08:27:02 UTC, Ola Fosheim Grøstad wrote:
> On Tuesday, 6 October 2015 at 06:45:47 UTC, Jonathan M Davis wrote:
>> On Monday, 5 October 2015 at 23:08:37 UTC, bitwise wrote:
>>> Well, again that has it's pros and cons. This is why I just want a normal language solution like DIP74.
>>
>> They're not the same thing at all. scoped is supposed to put the class on the stack, not the heap. And it's not ref-counted. It's so that you can create a class object in place, use it, and throw it away without doing any heap allocation. Essentially, it allows you to use a class as if it were a non-copyable struct. Even if we end up with ref-counting supported in the language, it doesn't obviate the need for scoped classes. They're for different use cases.
>
> Why not leave stack allocation of objects to the compiler, like inlining? Then add a "@stack" constraint that will make the compilation fail if the compiler is unable to put it on the stack?
>
> You need the compiler to prove that that the life time of the object is shorter than the stack frame in order to have memory safety anyway.

scoped is not designed with the idea that it's memory safe. scoped is very much an @system operation. And scoped is intended to replace scope classes in the language, so I don't think that any language support is going to be added for this. It's something that someone who knows what they're doing and needs that extra bit of efficiency can do, not something that's really intended to be in your average D program. In most cases, anything that's supposed to live on the stack should have been a struct anyway. It's just an issue when you want to use something on the stack in a particular case whereas it normally would be on the heap. And given D's lack of flow analysis and Walter's insistence on not adding it, I rather doubt that he's going to be big on the idea of having the compiler decide that it's safe to allocate a class object on the stack rather than the heap. But I don't remember him ever saying anything on that topic specifically.

- Jonathan M Davis
October 06, 2015
It's a step simpler with the new inline feature (works sadly only with the -inline flag):

----
pragma(inline, true)
auto scoped(T, Args...)(auto ref Args args) if (is(T == class)) {
    void[__traits(classInstanceSize, T)] buf = void;
    buf[] = typeid(T).init[];

    T obj = cast(T) buf.ptr;
    obj.__ctor(args);

    return obj;
}

class A {
    string name;

    this(string name) {
       this.name = name;
       writeln("Creating A");
    }

    ~this() {
       writeln("Destroying A");
    }

    void hello() {
       writeln("Hello, ", this.name);
    }
}

void main() {
    A a1 = scoped!A("Foo");
    a1.hello();
}
----