Issue with std.typecons.scoped and Interfaces

Andrew Wiley wiley.andrew.j at gmail.com
Tue Aug 16 00:10:20 PDT 2011


On Mon, Aug 15, 2011 at 11:31 PM, Jonathan M Davis <jmdavisProg at gmx.com>wrote:

> 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.
>

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.

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.
>

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.


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.
>

I am giving scoped the type of the derived class, not the base class or base
interface.


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.
>

Yes, it makes no sense to allocate an instance of an interface. I don't see
how that's relevant here.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20110816/b8ad93ab/attachment-0001.html>


More information about the Digitalmars-d mailing list