www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Checking function callability in D1 (aka static try-catch)

reply "Bill Baxter" <wbaxter gmail.com> writes:
This topic came up (again) fairly recently, and a solution was
proposed, but I found a case where that solution doesn't work.

The objective is to do a static check to see if something is callable
with particular argument types, and if so call it.

The proposed solution was to use '.init' like so:

    static if (is(typeof( some_function(ArgType.init) ))) {
        // call some_function , or make an alias to it or whatever
    }

But this doesn't always work if some function takes a ref argument.
For instance if ArgType is 'float', and some_function's signature is:

    void some_function(ref float);

Then it will fail.

The ugly workaround I found is to use this:

    static if (is(typeof( some_function(cast(ArgType)Object.init) ))) { ... }

First it's ugly, and second I'm not sure that really should work
anyway.  I don't think a 100% clever compiler would allow using
Object.init as a ref parameter even with a cast.

Any other ideas for how to test if a function is callable?  or is that
the best we can do?

Note that checking the type of the function itself is not acceptable,
because this is static duck-typing here -- you don't really care if
it's a function or delegate or a struct that implements opCall, as
long as you can call it.   And also you don't really care if the
argument is exactly ArgType, as long as the argument can be implicitly
converted from ArgType.

--bb
Dec 07 2008
parent reply Christian Kamm <kamm-incasoftware removethis.de> writes:
 This topic came up (again) fairly recently, and a solution was
 proposed, but I found a case where that solution doesn't work.
 
 The objective is to do a static check to see if something is callable
 with particular argument types, and if so call it.
 
 The proposed solution was to use '.init' like so:
 
     static if (is(typeof( some_function(ArgType.init) ))) {
         // call some_function , or make an alias to it or whatever
     }
 
 But this doesn't always work if some function takes a ref argument.
I didn't follow the original discussion, but what about: template makeValue(T...) { T makeValue; } template isCallable(alias s, ArgTy...) { const bool isCallable = is(typeof(s(makeValue!(ArgTy)))); }
Dec 07 2008
parent "Bill Baxter" <wbaxter gmail.com> writes:
On Sun, Dec 7, 2008 at 7:08 PM, Christian Kamm
<kamm-incasoftware removethis.de> wrote:
 This topic came up (again) fairly recently, and a solution was
 proposed, but I found a case where that solution doesn't work.

 The objective is to do a static check to see if something is callable
 with particular argument types, and if so call it.

 The proposed solution was to use '.init' like so:

     static if (is(typeof( some_function(ArgType.init) ))) {
         // call some_function , or make an alias to it or whatever
     }

 But this doesn't always work if some function takes a ref argument.
I didn't follow the original discussion, but what about: template makeValue(T...) { T makeValue; } template isCallable(alias s, ArgTy...) { const bool isCallable = is(typeof(s(makeValue!(ArgTy)))); }
That's pretty good. Thanks. Only problem is that it seems isCallable will generate an error. Seems an is() is needed at the call site. This seems to do the trick: private template makeValue(T...) { T makeValue; } private template Callable(alias s, ArgTy...) { static if (is(typeof(s(makeValue!(ArgTy))) FType)) { alias FType Callable; } else { static assert(false, s.stringof ~ " not callable with args "~ArgTy.stringof); } } ... static if (is(Callable!(some_function, ArgType))) { ... } --bb
Dec 07 2008