View mode: basic / threaded / horizontal-split · Log in · Help
July 16, 2012
Need runtime reflection?
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
Re: Need runtime reflection?
> 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
Re: Need runtime reflection?
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
Re: Need runtime reflection?
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
Re: Need runtime reflection?
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
Re: Need runtime reflection?
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
Re: Need runtime reflection?
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
Re: Need runtime reflection?
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
Re: Need runtime reflection?
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
Top | Discussion index | About this forum | D home