Issue with std.typecons.scoped and Interfaces

Jonathan M Davis jmdavisProg at gmx.com
Mon Aug 15 23:31:12 PDT 2011


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

It's not possible to use std.typecons.scoped with interfaces - and I mean that 
it can't possibly be implemented to do, not that it just doesn't do it right 
now.

Think about it. What is scoped doing? It's putting a class on the stack. In 
order to do that, it must know _exactly_ how much space the class requires in 
order to do that. It's effectively putting the class on the stack as if it were 
a struct. That means that what you're putting on the stack is _exactly_ the 
type that you use with scoped, _not_ what the type of the object actually is. 
If you use scoped with a class where the reference that you're using is not 
_exactly_ the type of the class that it refers to, you're going to get slicing 
( http://en.wikipedia.org/wiki/Object_slicing ) - which is one of the main 
reasons that classes don't go on the stack in the first place and why structs 
don't have inheritance.

If the type of the reference were a base class of the actual type being used, 
then any and all data which was not part of the base class would be lost. It 
creates an instance of the base class, _not_ the derived class. This is one of 
the reasons that std.typecons.scoped is _not_ safe. You _only_ use it when you 
need it for performance, you know that no reference to it is going to escape, 
and that no slicing is going to occur. Otherwise, you're going to have buggy 
code with undefined behavior.

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

- Jonathan M Davis


More information about the Digitalmars-d mailing list