Thread overview
passing duck-typed objects and retaining full type information
Nov 11, 2014
Adam Taylor
Nov 12, 2014
Freddy
Nov 12, 2014
Adam Taylor
Nov 12, 2014
Adam Taylor
Nov 12, 2014
Adam D. Ruppe
Nov 13, 2014
Jesse Phillips
November 11, 2014
* i apologize in advance, this is my first post -- the code formatting probably wont turn out so great...

I have a bunch of duck typed interfaces for "containers" similar to what you would find in std.range.

i.e.
template isContainer(C)
{
    enum bool isContainer = is(typeof(
    (inout int = 0)
    {
        C c = C.init;
	...					
    }));
}

template canRemoveFromContainer(C)
{
    enum bool canRemoveFromContainer = isContainer!C && is(typeof(
    (inout int = 0)
    {
        C c = C.init;
        c.remove();
    }));
}

Now what i want to do is pass some such "container" object to an interface function:

interface MyInterface
{
void filterCollisions(S)(S collisionCandidates)
    if(canRemoveFromContainer!S)
}

but of coarse templates and interfaces don't get along so well.  so...so far as I know i would need to do something like this:


interface MyInterface
{
final void filterCollisions(S)(S collisionCandidates)
    if(canRemoveFromContainer!S)
{
filterCollisionsImpl(...);
}

void filterCollisionsImpl(...)

}


and pass something to filterCollisionsImpl that is a "proper" class or interface type.

So here's the problem:  many of the "duck-typed" interfaces cannot be converted to proper interfaces without losing something.  So is there ANY way to pass in
a very basic class or interface Container type and call the remove function on it?  Here's what i've tried:

interface Container(C)
{
...
}

template ContainerObject(C) if (isContainer!(Unqual!C)) {
    static if (is(C : Container!(ElementType!C))) {
        alias ContainerObject = C;
    } else static if (!is(Unqual!C == C)) {
        alias ContainerObject = ContainerObject!(Unqual!C);
    } else {

    	static if (__traits(compiles, { enum e = C.ValueType; })) {
          alias ValueType = C.ValueType;
	} else {
	  alias ValueType = ElementType!C;
	}
		
        class ContainerObject : Container!ValueType {
            C _container;

            this(C container) {
                this._container = container;
            }

            static if(canRemoveFromContainer!C) {
              size_t remove()
	      {
	        return _container.remove();
	      }
            }
        }
    }
}

ContainerObject!C containerObject(C)(C container) if (isContainer!C) {
    static if (is(C : Container!(ElementType!C))) {
        return container;
    } else {
        return new ContainerObject!C(container);
    }
}


interface MyInterface
{
final void filterCollisions(S)(S collisionCandidates)
    if(canRemoveFromContainer!S)
{
  auto container = containerObject(collisionCandidates);
  container.remove();  // works just fine -- have the complete type info at instantiation site
  filterCollisionsImpl();
}

void filterCollisionsImpl(Container!string collisionCandidates)
collisionCandidates.remove(); // error -- some type info is lost here, only have a Container!string which doesn't have a remove function.
}
November 12, 2014
On Tuesday, 11 November 2014 at 19:23:39 UTC, Adam Taylor wrote:
> * i apologize in advance, this is my first post -- the code formatting probably wont turn out so great...
>
> I have a bunch of duck typed interfaces for "containers" similar to what you would find in std.range.
>
> i.e.
> template isContainer(C)
> {
>     enum bool isContainer = is(typeof(
>     (inout int = 0)
>     {
>         C c = C.init;
> 	...					
>     }));
> }
>
> template canRemoveFromContainer(C)
> {
>     enum bool canRemoveFromContainer = isContainer!C && is(typeof(
>     (inout int = 0)
>     {
>         C c = C.init;
>         c.remove();
>     }));
> }
>
> Now what i want to do is pass some such "container" object to an interface function:
>
> interface MyInterface
> {
> void filterCollisions(S)(S collisionCandidates)
>     if(canRemoveFromContainer!S)
> }
>
> but of coarse templates and interfaces don't get along so well.
>  so...so far as I know i would need to do something like this:
>
>
> interface MyInterface
> {
> final void filterCollisions(S)(S collisionCandidates)
>     if(canRemoveFromContainer!S)
> {
> filterCollisionsImpl(...);
> }
>
> void filterCollisionsImpl(...)
>
> }
>
>
> and pass something to filterCollisionsImpl that is a "proper" class or interface type.
>
> So here's the problem:  many of the "duck-typed" interfaces cannot be converted to proper interfaces without losing something.  So is there ANY way to pass in
> a very basic class or interface Container type and call the remove function on it?  Here's what i've tried:
>
> interface Container(C)
> {
> ...
> }
>
> template ContainerObject(C) if (isContainer!(Unqual!C)) {
>     static if (is(C : Container!(ElementType!C))) {
>         alias ContainerObject = C;
>     } else static if (!is(Unqual!C == C)) {
>         alias ContainerObject = ContainerObject!(Unqual!C);
>     } else {
>
>     	static if (__traits(compiles, { enum e = C.ValueType; })) {
>           alias ValueType = C.ValueType;
> 	} else {
> 	  alias ValueType = ElementType!C;
> 	}
> 		
>         class ContainerObject : Container!ValueType {
>             C _container;
>
>             this(C container) {
>                 this._container = container;
>             }
>
>             static if(canRemoveFromContainer!C) {
>               size_t remove()
> 	      {
> 	        return _container.remove();
> 	      }
>             }
>         }
>     }
> }
>
> ContainerObject!C containerObject(C)(C container) if (isContainer!C) {
>     static if (is(C : Container!(ElementType!C))) {
>         return container;
>     } else {
>         return new ContainerObject!C(container);
>     }
> }
>
>
> interface MyInterface
> {
> final void filterCollisions(S)(S collisionCandidates)
>     if(canRemoveFromContainer!S)
> {
>   auto container = containerObject(collisionCandidates);
>   container.remove();  // works just fine -- have the complete type info at instantiation site
>   filterCollisionsImpl();
> }
>
> void filterCollisionsImpl(Container!string collisionCandidates)
> collisionCandidates.remove(); // error -- some type info is lost here, only have a Container!string which doesn't have a remove function.
> }
Not entirly sure of what you asking for,but have you tried
inhertance?
----
interface Base(C){
     /+...+/
}

interface Derived(C):Base!C{
     /+...+/
}
----
November 12, 2014
> Not entirly sure of what you asking for,but have you tried
> inhertance?
> ----
> interface Base(C){
>      /+...+/
> }
>
> interface Derived(C):Base!C{
>      /+...+/
> }
> ----

No, i'm specifically looking for a solution that is NOT inheritance based.  I've been looking at solutions based on opDispatch or template mixins -- but so far haven't come up with anything.
November 12, 2014
> No, i'm specifically looking for a solution that is NOT inheritance based.  I've been looking at solutions based on opDispatch or template mixins -- but so far haven't come up with anything.

For example in this thread:
http://forum.dlang.org/thread/mailman.410.1319536838.24802.digitalmars-d@puremagic.com?page=2

Adam Ruppe has an interesting example:

DynamicObject delegate(DynamicObject[] args) dynamicFunctions;

DynamicObject opDispatch(string name, T...)(T t) {
     if(name !in dynamicFunctions) throw new MethodNotFoundException(name);
     DynamicObject[] args;
     foreach(arg; t)
          args ~= new DynamicObject(arg);

     return dynamicFunctions[name](args);
}
November 12, 2014
On Wednesday, 12 November 2014 at 01:50:07 UTC, Adam Taylor wrote:
> Adam Ruppe has an interesting example:

What that does is defer the type work to runtime, so a lot of type information is lost there too.

The big magic is that the wrapper object is a template, specialized for the compile time type, but once it is used it is still through an interface. This is similar to how the inputRangeObject+InputRange interface work in phobos http://dlang.org/phobos/std_range.html#inputRangeObject

Plain interface, templated implementation.


I don't really understand your question though....
November 13, 2014
On Tuesday, 11 November 2014 at 19:23:39 UTC, Adam Taylor wrote:
> Now what i want to do is pass some such "container" object to an interface function:
>
> interface MyInterface
> {
> void filterCollisions(S)(S collisionCandidates)
>     if(canRemoveFromContainer!S)
> }

You can't. This is one of the major restrictions of the template approach. Generics in C# allow for this, which I believe is reliant its JIT compiler.


Once you introduce the need for a vTable (which interfaces do) it is no longer possible to require implementation of a "phantom" function. Templates don't exist until their use, so it is not possible to require an entry in the vTable when the number of possible combinations is infinite.