Thread overview
Need runtime reflection?
Jul 16, 2012
lijie
Jul 17, 2012
David Piepgrass
Jul 18, 2012
lijie
Jul 18, 2012
Jacob Carlborg
Jul 18, 2012
lijie
Jul 18, 2012
Jacob Carlborg
Jul 18, 2012
lijie
Jul 18, 2012
Jacob Carlborg
Jul 18, 2012
Paulo Pinto
July 16, 2012
I want to imitate golang's interface in D, to study D's template. I wrote some code: https://gist.github.com/3123593

Now we can write code like golang:
--
interface IFoo {
    void foo(int a, string b, float c);
}

struct Foo {
    void foo(int a, string b, float c) {
        writeln("Foo.foo: ", a, ", ", b, ", ", c);
    }
}

struct FooFoo {
    void foo(int a, string b, float c) {
        writeln("FooFoo.foo: ", a, ", ", b, ", ", c);
    }
}

GoInterface!(IFoo) f = new Foo;
f.foo(3, "abc", 2.2);

f = new FooFoo;
f.foo(5, "def", 7.7);
--

It is also very naive, does not support some features, like out/ref parameters, free functions *[1]* and so on. The biggest problem is downcast not supported. In golang, we can write code like*[2]*:
--
var p IWriter = NewB(10)
p2, ok := p.(IReadWriter)
--

Seems [p.(IReadWriter)] dynamically build a virtual table *[3]*,because the
type of "p" is IWriter, it is *smaller* than IReadWriter, the cast
operation must search methods and build vtbl at run time.

In D, GoInterface(T).opAssign!(V)(V v) can build a rich runtime information
to *V* if we need. But if *V* is interface or base class, the type
information not complete. So, seems like I need runtime reflection? and how
can I do this in D? I did not find any useful information in the TypeInfo*.

------
[1] free functions support, e.g.
--
interface IFoo {
    void foo(int a, string b, float c);
}
void foo(int self, int a, string b, float c) {
    writefln("...");
}

GoInterface!(int) p = 1;
p.foo(4, "ccc", 6.6);
--
In theory no problem.

[2] example from
https://github.com/xushiwei/gobook/blob/master/dive-into/interface/03/interface.go
[3] /path/of/go/src/pkg/runtime/iface.c: static Itab* itab(InterfaceType
*inter, Type *type, int32 canfail)


Best regards,

-- Li Jie


July 17, 2012
> I want to imitate golang's interface in D, to study D's template. I wrote
> some code: https://gist.github.com/3123593
>
> Now we can write code like golang:
> --
> interface IFoo {
>     void foo(int a, string b, float c);
> }
>
> struct Foo {
>     void foo(int a, string b, float c) {
>         writeln("Foo.foo: ", a, ", ", b, ", ", c);
>     }
> }
>
> struct FooFoo {
>     void foo(int a, string b, float c) {
>         writeln("FooFoo.foo: ", a, ", ", b, ", ", c);
>     }
> }
>
> GoInterface!(IFoo) f = new Foo;
> f.foo(3, "abc", 2.2);
>
> f = new FooFoo;
> f.foo(5, "def", 7.7);
> --
>
> It is also very naive, does not support some features, like out/ref
> parameters, free functions *[1]* and so on. The biggest problem is downcast
> not supported. In golang, we can write code like*[2]*:
> --
> var p IWriter = NewB(10)
> p2, ok := p.(IReadWriter)
> --
>
> Seems [p.(IReadWriter)] dynamically build a virtual table *[3]*,because the
> type of "p" is IWriter, it is *smaller* than IReadWriter, the cast
> operation must search methods and build vtbl at run time.
>
> In D, GoInterface(T).opAssign!(V)(V v) can build a rich runtime information
> to *V* if we need. But if *V* is interface or base class, the type
> information not complete. So, seems like I need runtime reflection? and how
> can I do this in D? I did not find any useful information in the TypeInfo*.
>
> ------
> [1] free functions support, e.g.
> --
> interface IFoo {
>     void foo(int a, string b, float c);
> }
> void foo(int self, int a, string b, float c) {
>     writefln("...");
> }
>
> GoInterface!(int) p = 1;
> p.foo(4, "ccc", 6.6);
> --
> In theory no problem.

I, too, was enamored with Go Interfaces and implemented them for .NET:

http://www.codeproject.com/Articles/87991/Dynamic-interfaces-in-any-NET-language

And I wasn't the only one; later, someone else published another library for .NET with the exact same goal. This is definitely a feature I would want to see in D, preferably as a first-class feature, although sadly that would break any code that relies on ISomething being pointer-sized; Go uses fat pointers, and we use a thin-pointer implementation in .NET but it's inefficient (as every cast creates a heap-allocated wrapper, and double-indirection is needed to reach the real method.)

Anyway, they say it's possible to build runtime reflection in D but I've no idea how... has it never been done before?

Of course, runtime template instantiation won't be possible. Therefore, run-time casting will have to be more limited than compile-time casting.

Reflection to free functions would be really nice, but it might be less capable at run-time. Consider if you there is a class A in third-party module MA that you want to cast to interface I, but class A is missing a function F() from I. So in your module (module MB) you define a free function F(B) and now you can do the cast. I guess realistically this can only happen at compile-time, since a run-time cast would naturally only look in module MA, not MB, for functions it could use to perform the cast. Presumably, it also requires that MA requested a run-time reflection table to be built, and is it possible to build a reflection table for a module over which you have no control?

July 18, 2012
On Tue, Jul 17, 2012 at 11:08 PM, David Piepgrass <qwertie256@gmail.com>wrote:
>
> I, too, was enamored with Go Interfaces and implemented them for .NET:
>
> http://www.codeproject.com/**Articles/87991/Dynamic-** interfaces-in-any-NET-language<http://www.codeproject.com/Articles/87991/Dynamic-interfaces-in-any-NET-language>


Interesting, good article and project, thanks.

And I wasn't the only one; later, someone else published another library
> for .NET with the exact same goal. This is definitely a feature I would want to see in D, preferably as a first-class feature, although sadly that would break any code that relies on ISomething being pointer-sized; Go uses fat pointers, and we use a thin-pointer implementation in .NET but it's inefficient (as every cast creates a heap-allocated wrapper, and double-indirection is needed to reach the real method.)
>

D has powerful template and CTFE, seems we have more choices, fat pointer or thin pointer. I didn't think seriously about the performance differences.

About every cast creates a heap-allocated wrapper, I think we can try to use lower cost way in D. In my code:

--

    void opAssign(V)(GoInterface!(V) v) if (is(V == interface)) {
        //pragma(msg, "assign for GoInterface");
        static if (isImplicitlyConvertible!(V, T)) {
            //pragma(msg, V.stringof ~ " can implicitly convert to " ~
T.stringof);
            m_impl = v.m_impl;
        }
        else static if (isImplicitlyConvertible!(T, V)) {
            //pragma(msg, T.stringof ~ " can implicitly convert to " ~
V.stringof ~ ", try dynamic cast");
            if (v.m_impl is null) {
                m_impl = null;
            }
            else {
                m_impl = cast(T)(v.m_impl);
                if (m_impl is null) {
                    // dynamic cast failed, try dynamic proxy
                    m_impl = buildDynamicProxy!(V)(v);
                }
            }
        }
        else {
            //pragma(msg, "cannot implicitly between " ~ V.stringof ~
" and " ~ T.stringof);
            static if (isInterfaceConvertible!(V, T)) {
                //pragma(msg, "generate static proxy to convert " ~
V.stringof ~ " to " ~ T.stringof);
                m_impl = new StaticProxy!(V)(v.m_impl);
            }
            else {
                //pragma(msg, V.stringof ~ " not compatible " ~
T.stringof ~ ", must dynamic build call proxy");
                m_impl = buildDynamicProxy!(V)(v);
            }
        }
    }

--

Some cases we can directly do assignment, it also can be optimized to reduce heap allocation.


>
> Anyway, they say it's possible to build runtime reflection in D but I've no idea how... has it never been done before?


> Of course, runtime template instantiation won't be possible. Therefore, run-time casting will have to be more limited than compile-time casting.
>
> Reflection to free functions would be really nice, but it might be less capable at run-time. Consider if you there is a class A in third-party module MA that you want to cast to interface I, but class A is missing a function F() from I. So in your module (module MB) you define a free function F(B) and now you can do the cast. I guess realistically this can only happen at compile-time, since a run-time cast would naturally only look in module MA, not MB, for functions it could use to perform the cast. Presumably, it also requires that MA requested a run-time reflection table to be built, and is it possible to build a reflection table for a module over which you have no control?
>

Free functions support is hard, with runtime cast, I just think compile time.

I am trying to support free functions at compile time, is also hard, since the generator in gointerface module, but other modules are only visible in the module that used these modules. I have an ugly implementation used compile time string mixin, trying to simplify it. Fighting.


July 18, 2012
On Tuesday, 17 July 2012 at 15:08:18 UTC, David Piepgrass wrote:
>> I want to imitate golang's interface in D, to study D's template. I wrote
>> some code: https://gist.github.com/3123593
>>
>> Now we can write code like golang:
>> --
>> interface IFoo {
>>    void foo(int a, string b, float c);
>> }
>>
>> struct Foo {
>>    void foo(int a, string b, float c) {
>>        writeln("Foo.foo: ", a, ", ", b, ", ", c);
>>    }
>> }
>>
>> struct FooFoo {
>>    void foo(int a, string b, float c) {
>>        writeln("FooFoo.foo: ", a, ", ", b, ", ", c);
>>    }
>> }
>>
>> GoInterface!(IFoo) f = new Foo;
>> f.foo(3, "abc", 2.2);
>>
>> f = new FooFoo;
>> f.foo(5, "def", 7.7);
>> --
>>
>> It is also very naive, does not support some features, like out/ref
>> parameters, free functions *[1]* and so on. The biggest problem is downcast
>> not supported. In golang, we can write code like*[2]*:
>> --
>> var p IWriter = NewB(10)
>> p2, ok := p.(IReadWriter)
>> --
>>
>> Seems [p.(IReadWriter)] dynamically build a virtual table *[3]*,because the
>> type of "p" is IWriter, it is *smaller* than IReadWriter, the cast
>> operation must search methods and build vtbl at run time.
>>
>> In D, GoInterface(T).opAssign!(V)(V v) can build a rich runtime information
>> to *V* if we need. But if *V* is interface or base class, the type
>> information not complete. So, seems like I need runtime reflection? and how
>> can I do this in D? I did not find any useful information in the TypeInfo*.
>>
>> ------
>> [1] free functions support, e.g.
>> --
>> interface IFoo {
>>    void foo(int a, string b, float c);
>> }
>> void foo(int self, int a, string b, float c) {
>>    writefln("...");
>> }
>>
>> GoInterface!(int) p = 1;
>> p.foo(4, "ccc", 6.6);
>> --
>> In theory no problem.
>
> I, too, was enamored with Go Interfaces and implemented them for .NET:
>
> http://www.codeproject.com/Articles/87991/Dynamic-interfaces-in-any-NET-language
>

Interesting article, but why not just make use of "dynamic" interfaces?

--
Paulo
July 18, 2012
On 2012-07-18 06:10, lijie wrote:

> Free functions support is hard, with runtime cast, I just think compile
> time.

It's possibly to implement runtime reflection by loading the running executable and inspecting the symbol table. It's an ugly hack but it should work.

http://flectioned.kuehne.cn/

> I am trying to support free functions at compile time, is also hard,
> since the generator in gointerface module, but other modules are only
> visible in the module that used these modules. I have an ugly
> implementation used compile time string mixin, trying to simplify it.
> Fighting.

I think you can pass a module to a template via an alias parameter. Then the template should be able to inspect all free functions using something like __traits(allMembers).

-- 
/Jacob Carlborg


July 18, 2012
On Wed, Jul 18, 2012 at 2:59 PM, Jacob Carlborg <doob@me.com> wrote:

> On 2012-07-18 06:10, lijie wrote:
>
>  Free functions support is hard, with runtime cast, I just think compile
>> time.
>>
>
> It's possibly to implement runtime reflection by loading the running executable and inspecting the symbol table. It's an ugly hack but it should work.
>
> http://flectioned.kuehne.cn/


It is an optional way. I want to do all thing in D code.


>
>
>  I am trying to support free functions at compile time, is also hard,
>> since the generator in gointerface module, but other modules are only visible in the module that used these modules. I have an ugly implementation used compile time string mixin, trying to simplify it. Fighting.
>>
>
> I think you can pass a module to a template via an alias parameter. Then the template should be able to inspect all free functions using something like __traits(allMembers).


I didn't know this usage, I will try it. Thanks.


July 18, 2012
On 2012-07-18 09:26, lijie wrote:

> It is an optional way. I want to do all thing in D code.

You can do this in D.

-- 
/Jacob Carlborg


July 18, 2012
On Wed, Jul 18, 2012 at 2:59 PM, Jacob Carlborg <doob@me.com> wrote:

> I think you can pass a module to a template via an alias parameter. Then the template should be able to inspect all free functions using something like __traits(allMembers).
>
>
Have a problem.

--
// file: A.d

module A;

// functions and classes
--

--
// file: testtraits.d

import std.stdio;
import A;

void main() {
  writeln(__traits(allMembers, A));
}
--

There is a compilation error:
testtraits.d(6): Error: import A has no members

If module is under a package name, it is OK, is that a bug?


July 18, 2012
On 2012-07-18 17:10, lijie wrote:
> On Wed, Jul 18, 2012 at 2:59 PM, Jacob Carlborg <doob@me.com
> <mailto:doob@me.com>> wrote:
>
>     I think you can pass a module to a template via an alias parameter.
>     Then the template should be able to inspect all free functions using
>     something like __traits(allMembers).
>
>
> Have a problem.
>
> --
> // file: A.d
>
> module A;
>
> // functions and classes
> --
>
> --
> // file: testtraits.d
>
> import std.stdio;
> import A;
>
> void main() {
>    writeln(__traits(allMembers, A));
> }
> --
>
> There is a compilation error:
> testtraits.d(6): Error: import A has no members
>
> If module is under a package name, it is OK, is that a bug?
>

Seems like it.

http://d.puremagic.com/issues/

-- 
/Jacob Carlborg