<div class="gmail_quote">On Mon, Aug 15, 2011 at 11:31 PM, Jonathan M Davis <span dir="ltr"><<a href="mailto:jmdavisProg@gmx.com">jmdavisProg@gmx.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

<div><div></div><div class="h5">On Tuesday, August 16, 2011 02:03:45 Andrew Wiley wrote:<br>
> Sorry this is long, but it's a somewhat complicated issue that I think<br>
> someone who knows a lot about is() could solve very quickly. I hit this a<br>
> while back but didn't figure out exactly what the issue was until today. It<br>
> seems that std.typecons.scoped doesn't play nice with interfaces:<br>
><br>
> scopedtest.d (shortened somewhat):<br>
> import std.typecons, std.stdio;<br>
><br>
> class A {<br>
> this() { writeln("A"); }<br>
> ~this() { writeln("~A"); }<br>
> }<br>
><br>
> interface Bob {}<br>
><br>
> class ABob : A, Bob {<br>
> this() { writeln("ABob"); }<br>
> ~this() { writeln("~ABob"); }<br>
> }<br>
><br>
> void main() { auto abob = scoped!ABob(); }<br>
><br>
><br>
> compiler output:<br>
> $ gdc -o scopedtest scopedtest.d<br>
> /usr/include/d2/4.6.0/std/typecons.d:2571: Error: template<br>
> std.typecons.destroy(T) if (is(T == class)) does not match any function<br>
> template declaration<br>
> /usr/include/d2/4.6.0/std/typecons.d:2571: Error: template<br>
> std.typecons.destroy(T) if (is(T == class)) cannot deduce template function<br>
> from argument types !()(A,Bob)<br>
> /usr/include/d2/4.6.0/std/typecons.d:2530: Error: template instance<br>
> std.typecons.destroy!(ABob) error instantiating<br>
> scopedtest.d:18:        instantiated from here: scoped!(ABob,)<br>
> scopedtest.d:18: Error: template instance std.typecons.scoped!(ABob,) error<br>
> instantiating<br>
><br>
><br>
> std.typecons.destroy:<br>
> /*<br>
>   Used by scoped() above.  Calls the destructors of an object<br>
>   transitively up the inheritance path, but work properly only if the<br>
>   static type of the object (T) is known.<br>
>  */<br>
> private void destroy(T)(T obj) if (is(T == class))<br>
> {<br>
>     static if (is(typeof(obj.__dtor())))<br>
>     {<br>
>         obj.__dtor();<br>
>     }<br>
>     static if (!is(T == Object) && is(T Base == super))<br>
>     {<br>
>         Base b = obj;<br>
>         destroy(b); // <-- this instantiation is failing<br>
>     }<br>
> }<br>
><br>
><br>
> So it looks like instead of a single type, we're getting a tuple of some<br>
> sort because ABob has multiple "superclasses" ? I haven't played with tuples<br>
> enough to know exactly what's going on here.<br>
<br>
</div></div>It's not possible to use std.typecons.scoped with interfaces - and I mean that<br>
it can't possibly be implemented to do, not that it just doesn't do it right<br>
now.<br></blockquote><div><br></div><div>I think you misinterpreted my question (or I'm grossly misunderstanding your response). I'm allocating an instance of a class that happens to inherit from an interface. I realize that it makes no sense to ask scoped to allocate an instance of an interface. There's nothing to allocate. </div>

<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Think about it. What is scoped doing? It's putting a class on the stack. In<br>
order to do that, it must know _exactly_ how much space the class requires in<br>
order to do that. It's effectively putting the class on the stack as if it were<br>
a struct. That means that what you're putting on the stack is _exactly_ the<br>
type that you use with scoped, _not_ what the type of the object actually is.<br>
If you use scoped with a class where the reference that you're using is not<br>
_exactly_ the type of the class that it refers to, you're going to get slicing<br>
( <a href="http://en.wikipedia.org/wiki/Object_slicing" target="_blank">http://en.wikipedia.org/wiki/Object_slicing</a> ) - which is one of the main<br>
reasons that classes don't go on the stack in the first place and why structs<br>
don't have inheritance.<br></blockquote><div><br></div><div>I don't see how this is applicable here. I gave it the *exact* type I wanted (ABob), and it's allocating a struct based on that *exact* type that knows how to destroy the object when the scope exits. It just happens that the type I gave it inherits from an interface.</div>

<div> </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
If the type of the reference were a base class of the actual type being used,<br>
then any and all data which was not part of the base class would be lost. It<br>
creates an instance of the base class, _not_ the derived class. This is one of<br>
the reasons that std.typecons.scoped is _not_ safe. You _only_ use it when you<br>
need it for performance, you know that no reference to it is going to escape,<br>
and that no slicing is going to occur. Otherwise, you're going to have buggy<br>
code with undefined behavior.<br></blockquote><div><br></div><div>I am giving scoped the type of the derived class, not the base class or base interface.</div><div> </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">


An interface is the _worst_ base type that you could try and use with scoped.<br>
It has _no_ data. So, if std.typecons.scoped allowed you to use interfaces<br>
with it, then you would end up with a type with no data. Even worse, because<br>
you completely lose polymorphism when you use scoped (since you're dealing<br>
with the _exact_ type that you used with scoped), there aren't even any<br>
implementations of the interface's functions for it to use. The<br>
implementations were in the derived class which can sliced away. So, you have<br>
no data and no functions. You have nothing. So, std.typecons.scoped won't<br>
compile with interfaces. It wouldn't make any sense.<br></blockquote><div><br></div><div>Yes, it makes no sense to allocate an instance of an interface. I don't see how that's relevant here.</div></div><br>