131

I know the Function class can be passed as a parameter to another function, like this:

void doSomething(Function f) {
    f(123);
}

But is there a way to constrain the arguments and the return type of the function parameter?

For instance, in this case f is being invoked directly on an integer, but what if it was a function accepting a different type?

I tried passing it as a Function<Integer>, but Function is not a parametric type.

Is there any other way to specify the signature of the function being passed as a parameter?

Raibaz
  • 9,280
  • 10
  • 44
  • 65

6 Answers6

202

Dart v1.23 added a new syntax for writing function types which also works in-line.

void doSomething(Function(int) f) {
  f(123);
}

It has the advantage over the function-parameter syntax that you can also use it for variables or anywhere else you want to write a type.

void doSomething(Function(int) f) {
  Function(int) g = f;
  g(123);
}

var x = <int Function(int)>[];

int Function(int) returnsAFunction() => (int x) => x + 1;
    
int Function(int) Function() functionValue = returnsAFunction;
lrn
  • 64,680
  • 7
  • 105
  • 121
  • 7
    This is great, thanks! Anyways, this answers only first half of the question. How about the return types? – Ikar Pohorský Jul 02 '19 at 12:02
  • 6
    Added example of a return type which is a function type. – lrn Jul 02 '19 at 13:46
  • 1
    StreamSubscription listen(void onData(T event), {Function onError, void onDone(), bool cancelOnError}); - why are 2 different notations are used? What's the reason to use one or the other(onDone vs onError)? Maybe someone can add it to the answer? – yuranos Jul 12 '19 at 15:56
  • 1
    The `onError` parameter is set to accept a `Function` (the super-type of all functions) rather than a specific function type. That's because it accepts both `void Function(Object)` and `void Function(Object, StackTrace)`, and there is no way to represent that type union in the Dart type system. The remaining parameters can be typed with the specific function type needed. – lrn Jul 14 '19 at 20:15
  • 2
    As it's a little bit hidden in the answer, this is how to pass a typed function with return type as parameter in another function: `int outerFn(bool Function(String, bool) innerFn) { final result = innerFn("123", true); }` – sceee Aug 21 '20 at 07:57
  • Why not `Function` ?!!! ... Flutter is not intuitive.... – Ben Winding Aug 02 '21 at 14:53
  • What would you expect `Function` to mean? Generally `<...>` is used for type arguments to generic declaration. You can write `T Function(T)` for the type of generic functions that can map any type to itself. – lrn Aug 02 '21 at 20:02
30

To strongly type a function in dart do the following:

  1. Write down the Function keyword
Function
  1. Prefix it with its return type (for example void)
void Function
  1. Append it with parentheses
void Function()
  1. Put comma separated arguments inside the parentheses
void Function(int, int)
  1. Optionally - give names to your arguments
void Function(int foo, int bar)

Real life example:

void doSomething(void Function(int arg) f) {
    f(123);
}
Nabi Isakhanov
  • 429
  • 5
  • 6
21

Edit: Note that this answer contains outdated information. See Irn's answer for more up-to-date information.

Just to expand on Randal's answer, your code might look something like:

typedef void IntegerArgument(int x);

void doSomething(IntegerArgument f) {
    f(123);
}

Function<int> seems like it would be a nice idea but the problem is that we might want to specify return type as well as the type of an arbitrary number of arguments.

Richard Ambler
  • 4,816
  • 2
  • 21
  • 38
12

For reference.

int execute(int func(int a, int b)) => func(4, 3);

print(execute((a, b) => a + b));
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Jans
  • 11,064
  • 3
  • 37
  • 45
10

You can have a function typed parameter or use a typedef

void main() {
  doSomething(xToString);
  doSomething2(xToString);
}

String xToString(int s) => 's';

typedef String XToStringFn(int s);

void doSomething(String f(int s)) {
    print('value: ${f(123)}');
}

void doSomething2(XToStringFn f) {
    print('value: ${f(123)}');
}

DartPad example

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
8

This is what typedefs are for!

Randal Schwartz
  • 39,428
  • 4
  • 43
  • 70