www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - guard condition for a callable thingy, with THESE arguments

reply cy <dlang verge.info.tm> writes:
I take callbacks on occasion, and I don't really care if they're 
a delegate, or a function, or a callable object, and I can assert 
that in a template:

void foo(Callable)(Callable callback) if(isSomeFunction!Callable 
|| isCallable!Callable) {
  ...
}

That works, but it doesn't show you what arguments the callable 
will take, or how many, or what its return type should be.

You can of course read the body of the `foo` function to spy out 
where the text "callable(" might be, but it'd be really nice if I 
could put that information in my guard condition somehow. What I 
want is something like this.

bool default_callback(int foo, string bar, Something baz) {
  ...
}

void foo(Callable)(Callable callback) 
if(calledTheSameAs!(Callable,default_callback)) {
  ...
}

or

void foo(Callable)(Callable callback) 
if(calledTheSameAs!(Callable,bool function(int,string,Something)) 
{
  ...
}

Is that possible to do? Has it already been done?
May 14 2016
parent reply Ann W. Griffith <awgreataw online.us> writes:
On Sunday, 15 May 2016 at 01:59:15 UTC, cy wrote:
 I take callbacks on occasion, and I don't really care if 
 they're a delegate, or a function, or a callable object, and I 
 can assert that in a template:

 void foo(Callable)(Callable callback) 
 if(isSomeFunction!Callable || isCallable!Callable) {
  ...
 }

 That works, but it doesn't show you what arguments the callable 
 will take, or how many, or what its return type should be.

 You can of course read the body of the `foo` function to spy 
 out where the text "callable(" might be, but it'd be really 
 nice if I could put that information in my guard condition 
 somehow. What I want is something like this.

 bool default_callback(int foo, string bar, Something baz) {
  ...
 }

 void foo(Callable)(Callable callback) 
 if(calledTheSameAs!(Callable,default_callback)) {
  ...
 }

 or

 void foo(Callable)(Callable callback) 
 if(calledTheSameAs!(Callable,bool 
 function(int,string,Something)) {
  ...
 }

 Is that possible to do? Has it already been done?
use "Parameters" in the constraint or make a template that you can reeuse. ---- import std.traits; alias Model = void function(int, string); void foo(Callable)(Callable callback) if(is(Parameters!Callable == Parameters!Model)) {} void main(string[] args) { static void right(int,string){} static assert(__traits(compiles, foo(&right))); static void wrong(int){} static assert(!__traits(compiles, foo(&wrong))); } ----
May 14 2016
parent reply cy <dlang verge.info.tm> writes:
On Sunday, 15 May 2016 at 02:12:38 UTC, Ann W. Griffith wrote:
 use "Parameters" in the constraint or make a template that you 
 can reeuse.
This is what I've got going so far. Using static asserts to have clearer errors when an incorrect callback is supplied. I'm not... sure storage class is important. import std.traits: isSomeFunction, isCallable, ParameterTypeTuple, ParameterStorageClassTuple, ReturnType, isDelegate; import std.stdio; template isCompatibleFunction(alias Src, alias Dest) { static assert(isSomeFunction!Src || isCallable!Src, "Source is not callable"); static assert(isSomeFunction!Dest || isCallable!Dest, "Destination is not callable"); static assert(is(ParameterTypeTuple!Src == ParameterTypeTuple!Dest), "Type Tuples differ"); pragma(msg,ParameterStorageClassTuple!Src == ParameterStorageClassTuple!Dest); static assert(ParameterStorageClassTuple!Src == ParameterStorageClassTuple!Dest, "Storage classes differ"); static assert(is(ReturnType!Src == ReturnType!Dest), "Return type differs"); immutable bool isCompatibleFunction = true; } bool function_callback(string a) { return true; } template foobar(Callable) if(isCompatibleFunction!(function_callback,Callable)) { template foobar(Callable c) { immutable bool foobar = c("foo"); } } void main() { bool result = true; bool delegate_callback(string a) { return result; } bool delegate(string) dg = &delegate_callback; static assert(isDelegate!dg); static assert(isCompatibleFunction!(function_callback, delegate_callback)); struct Derp { static bool opCall(string a) { return true; } bool opCall(string a) { return false; } bool member(string a) { return true; } }; static assert(isCompatibleFunction!(function_callback,Derp.init.member)); static assert(isCompatibleFunction!(function_callback,Derp.init)); static assert(isCompatibleFunction!(function_callback,Derp)); static assert(isCompatibleFunction!(delegate_callback,Derp)); if(foobar!function_callback) { writeln("foo"); } else { writeln("bar"); } writeln("derp"); }
May 15 2016
parent Ann W. Griffith <awgreataw online.us> writes:
On Sunday, 15 May 2016 at 07:22:57 UTC, cy wrote:
 On Sunday, 15 May 2016 at 02:12:38 UTC, Ann W. Griffith wrote:
 use "Parameters" in the constraint or make a template that you 
 can reeuse.
This is what I've got going so far. Using static asserts to have clearer errors when an incorrect callback is supplied. I'm not... sure storage class is important.
It could be important, especially "ref" and "out" that could lead to UB if not checked, without compile error. "shared" also but when supplied, invalid callback will not compile.
May 15 2016