www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to call a delegate held in a Variant array?

reply "Gary Willoughby" <dev nomad.so> writes:
How to call a delegate held in a Variant array? I'm toying with 
some dynamic delegate code and wondered if i put a delegate in a 
Variant how would i call it?

class C
{
	private Variant[string] _methods;

	public void addMethod(T)(string name, T func)
	{
		this._methods[name] = func;
	}
}

auto obj = new C();

obj.addMethod("test", delegate(){
	return 34;
});

Now, how do i call the delegate held in 'this._methods["test"]'?
Sep 10 2013
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Sep 10, 2013 at 10:09:33PM +0200, Gary Willoughby wrote:
 How to call a delegate held in a Variant array? I'm toying with some
 dynamic delegate code and wondered if i put a delegate in a Variant
 how would i call it?
 
 class C
 {
 	private Variant[string] _methods;
 
 	public void addMethod(T)(string name, T func)
 	{
 		this._methods[name] = func;
 	}
 }
 
 auto obj = new C();
 
 obj.addMethod("test", delegate(){
 	return 34;
 });
 
 Now, how do i call the delegate held in 'this._methods["test"]'?
My first guess would be: _methods["test"](); Or does that not work? T -- Старый друг лучше новых двух.
Sep 10 2013
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 10 September 2013 at 21:16:56 UTC, H. S. Teoh wrote:
 My first guess would be: _methods["test"]();
Variant doesn't wrap the function and thus won't know how to call it; it doesn't implement opCall, and even if it did, it won't know types the arguments and return value are. My guess would be to get the static type: auto dg = v.get!(void delegate()); dg(); ........ except this is throwing at runtime: Variant: attempting to use incompatible types void()* and void()* Ugh, that's annoying. Maybe using Variant isn't the right way. The technique I use to for storing random methods is to store a wrapper function instead. The wrapper function converts all the arguments into one common type (e.g. Variant) so then your methods array can be one type of delegate instead of a Variant[]. Variant delegate(Variant[] args)[] _methods; public void addMethod(T)(string name, T func) { this._methods ~= delegate Variant(Variant[] args) { import std.traits; import std.conv; ParameterTypeTuple!func argTuple; foreach(idx, arg; argTuple) { argTuple = args[idx].get!(typeof(arg)); } Variant returned; static if(is(ReturnType!func == void)) func(argTuple); else returned = func(argTuple); return returned; }; } Then, when you call it, the static type of the methods wrapper is always the same and you can handle arguments and return value by wrapping/unwrapping the Variants. You might have to cast away const when assigning to the argTuple or prepopulate it with default arguments, etc. The code here will work in simple cases though to get you started.
Sep 10 2013