20

Can you pass a function as a parameter in Solidity?

My guess: There is the concept of address in Solidity, but they represent contracts. Contracts can have fallback functions, but I don't think you can give them parameters. Thinking about passing the function as a parameter by address like you would do in C.

Is there a legit way to pass functions as parameters, or if not, is there a hacky way?

If there is, how? And if there isn't, why not?

  • Solidity is too costly for functional programming – niksmac Apr 25 '16 at 17:53
  • I understand that a lot of functional programming concepts like functional composition might be too expensive, but I'm curious specifically if passing functions is too expensive. Passing a pointer to a function should be pretty cheap. – Karl Floersch Apr 25 '16 at 17:57
  • Both are different function as a parameter and functional programming right? – niksmac Apr 25 '16 at 17:59
  • Yeah they are different. Passing functions as a parameter is just a helpful technique that functional programming languages utilize. For instance, you can pass a function as a parameter in C, but you wouldn't really call C a functional programming language. – Karl Floersch Apr 25 '16 at 18:03
  • 2
    @NikhilM : " Solidity is too costly for functional programming " Just curious can you explain more why it's too costly? – dbryson Apr 25 '16 at 18:19
15

Functions (aka Methods) are specified by the ABI, and have a Method ID, which is the first 4 bytes of the sha3 (Keccak-256) of the method's signature.

Here's an example of invoking someFunction on contract: contract.call(bytes4(sha3("someFunction()")))

Here is a tested function with passing a methodId as a parameter:

contract C1 {
    uint public _n;  // public just for easy inspection in Solidity Browser

    function foo(uint n) returns(uint) {
        _n = n;
        return _n;
    }

    function invoke(bytes4 methodId, uint n) returns(bool) {
        return this.call(methodId, n);
    }
}

Test it in Solidity Browser by using "0x2fbebd38", 9 as the parameters to invoke, then see that _n equals 9.

Notes:

  • 0x2fbebd38 is the result of bytes4(sha3("foo(uint256)")) (don't forget the need to use canonical types, in this case uint256, per the ABI.)

  • Return values from call and callcode are boolean, either the call succeeded or the call failed. It is not possible to return a value from call since that would require the contract to know the return type beforehand.

  • 1
    Of course, that's an external function - internal ones exist too, and passing a pointer to one would be a different matter entirely... – Nick Johnson Apr 26 '16 at 14:09
  • It seems you can see this technique being used here: github.com/nexusdev/dappsys/blob/… – Karl Floersch Apr 28 '16 at 1:26
  • 3
    This method has two drabacks: 1) costs way more gas, 2) is treated as call from "external" and hence non-accessible if target function is marked "internal" – Validity Labs - Sebastian May 1 '17 at 16:15
7

To add on to Nick Johnson's answer, function types in recent versions of solidity allow you to describe function pointers now:

http://solidity.readthedocs.io/en/latest/types.html#function-types

Function types are the types of functions. Variables of function type can be assigned from functions and function parameters of function type can be used to pass functions to and return functions from function calls. Function types come in two flavours - internal and external functions

6

eth's answer applies to external function calls (between contracts, or by using the external interface to call your own contract); here I'll attempt to answer for internal function calls.

Solidity currently provides no syntax for describing the type of a function pointer, so you can't take them as arguments or return values. However, functions are first-class and can be assigned to variables using var; here's the example from the Solidity user manual:

contract FunctionSelector {
  function select(bool useB, uint x) returns (uint z) {
    var f = a;
    if (useB) f = b;
    return f(x);
  }
  function a(uint x) returns (uint z) {
    return x * x;
  }
  function b(uint x) returns (uint z) {
    return 2 * x;
  }
}
  • 1
    Thanks for helpful answer :) I thought there might be other angles and I didn't internalize that part of the docs to remember it. – eth Apr 26 '16 at 18:43
  • Not sure when that changed, but this is not correct anymore, as it seems at least as early as 0.4.16 solidity does provide syntax for describing the type of functions, so you can pass them as arguments (solidity.readthedocs.io/en/v0.4.24/types.html), see Michael's answer – user1282931 Aug 22 '18 at 12:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.