October 28, 2014
On Tue, 28 Oct 2014 01:36:01 +0000
bitwise via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> I have actually found a work around as well, which was to wrap the actual retrieval of the function address in a lambda, and pass the lambda by template parameter instead:
it's not a "workaround", it's almost exactly what i did in my sample, just not that hairy.

you can't get address of anything in compile time, 'cause there is no such address. but you can do it in runtime, of course. that's what you doing: postponing "&" to runtime.

> as far as I could google, no one has attempted this yet.
no one published it yet, not "no one attempted". i desperately need runtime reflection for my (still private) component builder project, so i'm slowly writing that mechanics. and my "command console" using similar technique to allow user inspect variables and classes, and call function/methods in runtime.

yet the thing is still in post-alpha stage (but it works). i also found
some compiler bugs while writing it, but not yet filled bugreports (i
know, i know, i shouldn't be so lazy).

> My prototype works pretty much as he has described, less a feature here and there.
ah, that's good. i'm not aiming for full reflection mechanics, but i want to have it. ;-)


October 28, 2014
On Tuesday, 28 October 2014 at 02:34:14 UTC, ketmar via Digitalmars-d wrote:
> On Tue, 28 Oct 2014 01:36:01 +0000
> bitwise via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
>> I have actually found a work around as well, which was to wrap the actual retrieval of the function address in a lambda, and pass the lambda by template parameter instead:
> it's not a "workaround", it's almost exactly what i did in my sample,
> just not that hairy.
>
> you can't get address of anything in compile time, 'cause there is no
> such address. but you can do it in runtime, of course. that's what you
> doing: postponing "&" to runtime.
>
>> as far as I could google, no one has attempted this yet.
> no one published it yet, not "no one attempted". i desperately need
> runtime reflection for my (still private) component builder project, so
> i'm slowly writing that mechanics. and my "command console" using
> similar technique to allow user inspect variables and classes, and call
> function/methods in runtime.

I do something possibly similar for generating console help text using runtime reflection. It could have used compile-time reflection, but it gets annoying to use.

Using https://shardsoft.com/stash/projects/SHARD/repos/dap/browse/source/dap/Standalone.d (with https://shardsoft.com/stash/projects/SHARD/repos/shardtools/browse/source/ShardTools/CommandLine.d and https://shardsoft.com/stash/projects/SHARD/repos/shardtools/browse/source/ShardTools/Reflection.d?until=45ded3019f3f05d7b68e5746d34da1de7433ccf6), it generates something like:

D Asset Pipeline
Converts assets into an intermediate post-processed format more efficiently loaded at runtime.
Commands:
        [-h|--help]: Displays the help string.
        [-a|--add]: Adds the given raw asset to the asset store using the default processor and default settings.
        [-r|--remove]: Removes the asset with the specified qualified name from the asset store.
        [-l|--list]: Lists all assets currently stored.
        [-b|--build]: Builds all dirty assets using current settings.
        [-i|--inspect]: Shows all properties of the given asset.
        [-m|--modify]: Modifies a property of a processor on an asset, or the processor used to build the asset.
Options:
        [--input-folder]: The folder that assets should be read from and settings stored in. Default: Content\Input
        [--output-folder]: The folder that generated assets should be saved to. Default: Content\Output
        [--log-level]: The minimum severity for a message to be logged. Default: info


The command lines then invoke methods registered through runtime reflection, which allow the user to change individual properties on the set processor using --modify, again using runtime reflection to find the setting that the user wants and converting their input to the appropriate type.
October 28, 2014
On Monday, 27 October 2014 at 22:17:25 UTC, bitwise wrote:

> This error seems like it may be related some how:
>
> enum index = __traits(getVirtualIndex, TestClass.instanceMethod);
> enum p = TestClass.classinfo.vtbl[index];
>
> The above code will produce this error:
> Error: typeid(main.TestClass).vtbl is not yet implemented at
> compile time
>
> but if this is the problem, shouldn't Both of the test cases fail?

You shouldn't need the vtbl at compile-time, only the index of the method. The method indices within the vtbl are computed, which is what getVirtualIndex gives you, but CTFE doesn't support directly accessing the vtbl yet. That being said, you only need to worry about any of this if you want to support virtual methods and have it invoke the actual overridden method, not the one you have saved through reflection. (For example, if Bar : Foo overrides foo, and you generated reflection info for Foo, it would call Foo.foo instead of Bar.foo even if passed in an instance of Bar.)

It's hard to tell exactly what you're trying to do in your original code, but one thing to keep in mind is that something like Foo!(TestClass.TestInstance) may mean multiple things, as the method has overloads. At some point you may need to use __traits(getOverloads) (such as in https://shardsoft.com/stash/projects/SHARD/repos/shardtools/browse/source/ShardTools/Reflection.d?until=45ded3019f3f05d7b68e5746d34da1de7433ccf6#1202) to get the actual methods which you can then get a function pointer for (again though, requires more effort for properly handling virtual methods).
October 29, 2014
On Tuesday, 28 October 2014 at 02:34:14 UTC, ketmar via
Digitalmars-d wrote:
> On Tue, 28 Oct 2014 01:36:01 +0000
> bitwise via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
>> I have actually found a work around as well, which was to wrap the actual retrieval of the function address in a lambda, and pass the lambda by template parameter instead:
> it's not a "workaround", it's almost exactly what i did in my sample,
> just not that hairy.

Yea... I've tried several ways to clean this up.. the most
favorable being this:

MethodImpl!({ return &__traits(getMethod, SCOPE, m); })(...);

But, although the above has worked for me in a trivial test case,
it won't compile with my reflection implementation right now.
Definitely on the list though.


> no one published it yet, not "no one attempted". i desperately

publish or perish! =)

> yet the thing is still in post-alpha stage (but it works).

Yeah.. mine too.. I have only really been testing the common
cases. Not looking forward to unit-test time...

> i also found some compiler bugs while writing it, but not yet filled bugreports

I've hit a few myself... but the compiler messages have been a
bit obscure.. so I'm not even sure how to classify some of
the bugs I've hit.

I think should classify the one in the OP as something like:
"inconsistent availability of function pointers at compile time"
October 29, 2014
> That being said, you only need to worry about any of this if you want to support virtual methods and have it invoke the actual overridden method, not the one you have saved through reflection. (For example, if Bar : Foo overrides foo, and you generated reflection info for Foo, it would call Foo.foo instead of Bar.foo even if passed in an instance of Bar.)

I understand what you mean, but I don't think I need to, or should support that based on my current design.

Methods can be retrieved/invoked like this:

getModule("test").getClass("Bar").getMethod("foo").invoke(cast(void*)new Bar);

above, you would be explicitly asking for the version of 'foo' which is callable from an instance of 'Bar'.

i.e. Each instance of MethodDeclImpl retrieved from my reflection system represents exactly one method.

the type of the instance passed in will eventually be checked, and invoke() will throw an exception if the instance is of the wrong type.

In the case of a base pointer, one could use the following code:

Foo bar = new Bar;

foreach(c; getModule("test").classes)
{
    if(typeid(bar) == c.type)
        c.findMethod("foo").invoke(cast(void*)bar);
}

However, I would like to eventually have something more elegant than this.



> one thing to keep in mind is that something like Foo!(TestClass.TestInstance) may mean multiple things, as the method has overloads. At some point you may need to use __traits(getOverloads) (such as in

This was next on the list =)

I just pushed support for overloaded functions, and added tests for virtual functions.


October 29, 2014
On 10/27/14 4:52 PM, bitwise wrote:
>>> quotes self
>
> Here is a better example, showing that virtual function pointers are
> available at compile time in C++. Essentially, I would expect my D code
> to function similarly, but it won't compile.
>
> class TestAddr {
>      public: virtual void test() { cout << "test" << endl; }
> };
>
> template<void (TestAddr::*FN)()>
> class PtrWrapper
> {
> public:
>      void invoke(TestAddr *instance) { (instance->*FN)(); }
> };
>
> int main(int argc, const char * argv[])
> {
>      TestAddr test;
>      PtrWrapper<&TestAddr::test> wrapper;
>      wrapper.invoke(&test);
>      return 0;
> }

That won't work in D because in D pointers to methods carry "this" with them, whereas in C++ they don't. -- Andrei
October 29, 2014
On Wed, 29 Oct 2014 00:13:52 +0000
bitwise via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> > no one published it yet, not "no one attempted". i desperately
> publish or perish! =)
oh, i want it to be at least pre-beta before showing it to the world. ;-) what i'm really aiming at is a system like BlackBox Component Builder (it's alot of work, but at least it's fun).

> > yet the thing is still in post-alpha stage (but it works).
> Yeah.. mine too.. I have only really been testing the common cases. Not looking forward to unit-test time...
lucky me, my system doesn't need full-featured runtime reflection, only some easy cases for classes, structs and free functions.

and i'm not event started to mess with shared libraries yet, which are the next key element of my project.


October 29, 2014
On Wednesday, 29 October 2014 at 01:22:43 UTC, Andrei Alexandrescu wrote:
> That won't work in D because in D pointers to methods carry "this" with them, whereas in C++ they don't. -- Andrei

I have an idea ! We should call them delegates so people won't make the confusion !
October 29, 2014
Though, explicit reference to TestClass.instanceMethod is not a delegate. The delegate is constructed manually later in the code on attempt to call the method.
October 29, 2014
I think I've got it figured out.

In my original example, I added the following line inside the function-template, and the class-template:

pragma(msg, typeof(T).stringof);

in both cases, the (correct)result was a tuple of a function (void())

But, when it came time to retrieve the address of the function, the behaviour was not the same inside the scope of the function, and the class.

this line behaved differently in both cases:

dg.funcptr = &T[0];

inside the function-template, the above line worked correctly, and the function's address was taken. However, inside the class-template, the compiler attempted to call T[0] which yielded this error:

Error: this for instanceMethod needs to be type TestClass not type main.FuncPtr!(instanceMethod).FuncPtr

So, at this point, I saw that the compiler was not parsing things in a consistent way, and came up with this template:

template addressOf(T...) {
    enum addressOf = &T[0];
}

Finally, my example worked as expected after making this change:

dg.funcptr = &T[0];
to
dg.funcptr = addressOf!(T[0]);


Onward..

Given that my current project is a reflection library, I proceeded to start swapping in __traits.

All of these worked correctly (class methods):

invokeFunction!(__traits(getMember, TestClass, "instanceMethod"))(cast(void*)testClass);
invokeFunction!(__traits(getMember, TestClass, "staticMethod"))(null);
auto fp1 = new FuncPtr!(__traits(getMember, TestClass, "instanceMethod"));
auto fp2 = new FuncPtr!(__traits(getMember, TestClass, "staticMethod"));

But these did not(global methods).

invokeFunction!(__traits(getMember, thisModule, "GlobalMethod"))(null);
auto fp3 = new FuncPtr!(__traits(getMember, thisModule, "GlobalMethod"));

Both of the above lines failed with the following error:

Error: function main.GlobalMethod () is not callable using argument types (void)



So finally, I would describe these bugs as follows:

1) the addressOf(T...) template should not be needed inside the class-template. Both cases in the original post should behave consistently. The problem is inconsistent handling of template arguments between function templates and class templates.

2) the return of __traits(getMember) is not treated the same way as the symbol itself when parsed. In the case of GlobalMethod, the compiler tries to call the method when it's returned from a __trait, but does not when it's referenced directly.

Does anyone concur with these diagnoses?

And is there any way in D to explicitly request that a function not be called without parens?

1 2
Next ›   Last »