flutter
/

Dart Callable Classes – Making Instances Callable Like Functions

Last Sync: Today

On this page

12
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Dart Callable Classes – Making Instances Callable Like Functions

What is a Callable Class?

A callable class is a class that defines a call method. When an instance of such a class is invoked like a function (i.e., using parentheses with arguments), the call method is executed. This feature allows objects to behave like functions, enabling you to use them as callbacks, create function‑like objects with state, and build expressive APIs.

Defining a Callable Class

To make a class callable, simply add a method named call. It can have any parameters and return type. The method can be synchronous or asynchronous.

DARTRead-only
1
class Greeter {
  String name;
  Greeter(this.name);

  // The call method – makes instances callable
  void call() {
    print('Hello, I am $name');
  }
}

void main() {
  var greeter = Greeter('Alice');
  greeter(); // Calls the `call` method
}

Call Method with Parameters

The call method can accept parameters, just like a regular function. This allows you to use your callable objects as custom functions.

DARTRead-only
1
class Adder {
  int addBy;

  Adder(this.addBy);

  int call(int x) => x + addBy;
}

void main() {
  var add5 = Adder(5);
  print(add5(10)); // 15

  var add10 = Adder(10);
  print(add10(7)); // 17
}

Named and Optional Parameters

You can use all Dart parameter features in the call method: positional, optional, named, required, etc. This makes callable objects flexible.

DARTRead-only
1
class Logger {
  void call(String message, {String level = 'INFO'}) {
    print('[$level] $message');
  }
}

void main() {
  var log = Logger();
  log('App started'); // [INFO] App started
  log('Error occurred', level: 'ERROR'); // [ERROR] Error occurred
}

Callable Classes as Callbacks

Because callable objects behave like functions, they can be used anywhere a function is expected, such as callbacks for forEach, map, or custom APIs.

DARTRead-only
1
class Multiplier {
  final int factor;
  Multiplier(this.factor);

  int call(int x) => x * factor;
}

void main() {
  var numbers = [1, 2, 3, 4];
  var doubleIt = Multiplier(2);
  var tripled = numbers.map(Multiplier(3)).toList();

  print(numbers.map(doubleIt).toList()); // [2, 4, 6, 8]
  print(tripled); // [3, 6, 9, 12]
}

Stateful Callable Objects

One powerful aspect of callable classes is that they can maintain state across invocations. This is like a closure, but with explicit fields and methods.

DARTRead-only
1
class Counter {
  int _count = 0;

  int call() {
    return ++_count;
  }
}

void main() {
  var counter = Counter();
  print(counter()); // 1
  print(counter()); // 2
  print(counter()); // 3
}

Generic Callable Classes

You can make your callable classes generic, allowing them to work with different types while preserving type safety.

DARTRead-only
1
class Parser<T> {
  T Function(String) parser;

  Parser(this.parser);

  T call(String input) => parser(input);
}

void main() {
  var intParser = Parser<int>((s) => int.parse(s));
  var doubleParser = Parser<double>((s) => double.parse(s));

  print(intParser('42')); // 42
  print(doubleParser('3.14')); // 3.14
}

Async Callable Classes

The call method can be async or return a Future, making the object callable asynchronously.

DARTRead-only
1
class DelayPrinter {
  Duration delay;

  DelayPrinter(this.delay);

  Future<void> call(String message) async {
    await Future.delayed(delay);
    print(message);
  }
}

void main() async {
  var printer = DelayPrinter(Duration(seconds: 1));
  await printer('Hello after 1 second');
}

Use Cases

    • Function‑like objects with configuration: e.g., multipliers, loggers with level.
    • Stateful callbacks: counters, accumulators, caches.
    • Fluent DSLs: design APIs where objects can be called with parentheses.
    • Dependency injection: replace simple functions with more complex objects.
    • Mocking: create test‑friendly callable objects that track calls.

Best Practices

    • Use callable classes when you need state or configuration that a simple function cannot provide.
    • Keep the call method focused; avoid side effects unless intended.
    • Document the expected usage (especially if the object is used as a callback).
    • Use generic callable classes to maintain type safety when working with multiple types.

Complete Example

DARTRead-only
1
class Operation {
  final String name;
  final int Function(int, int) _operation;

  Operation(this.name, this._operation);

  int call(int a, int b) {
    print('Executing $name');
    return _operation(a, b);
  }
}

void main() {
  var add = Operation('Addition', (a, b) => a + b);
  var multiply = Operation('Multiplication', (a, b) => a * b);

  print(add(5, 3)); // Executing Addition
                    // 8
  print(multiply(5, 3)); // Executing Multiplication
                         // 15
}

Key Takeaways

    • Implement the call method to make a class callable.
    • Callable objects can be used anywhere a function is expected.
    • They can have state, configuration, and generic parameters.
    • Use callable classes for function‑like objects that need more than just a function.

Try it yourself

class Multiplier {
  final int factor;
  Multiplier(this.factor);
  int call(int x) => x * factor;
}

void main() {
  var doubleIt = Multiplier(2);
  var numbers = [1, 2, 3];
  print(numbers.map(doubleIt).toList()); // [2, 4, 6]
}

Test Your Knowledge

Q1
of 4

What method must be implemented to make a class callable?

A
apply
B
invoke
C
call
D
execute
Q2
of 4

What is the output of this code? class Adder { int addBy; Adder(this.addBy); int call(int x) => x + addBy; } void main() { var add5 = Adder(5); print(add5(10)); }

A
5
B
10
C
15
D
Error
Q3
of 4

Can a callable class have named parameters?

A
Yes
B
No
C
Only if the class is generic
D
Only in Dart 3.0+
Q4
of 4

What is a key advantage of a callable class over a simple function?

A
It can be used as a callback
B
It can maintain state across invocations
C
It can be asynchronous
D
It can be called with parentheses

Frequently Asked Questions

Can a class have more than one `call` method?

No, a class can have only one method named call. However, you can use method overloading by using optional parameters or named parameters to vary the signature.

What is the difference between a callable class and a closure?

A closure is a function that captures variables from its surrounding scope. A callable class is an object with a call method. Both can be used as functions, but the class can have multiple methods, fields, and can be passed around more explicitly. Use callable classes when you need more structure or when you want to reuse the same logic with different configurations.

Can a callable class be used as a type for a function parameter?

Yes, because the instance itself is a valid object, and Dart will treat it as a function. For example, you can pass a callable object to a function expecting a void Function().

Is it possible to make a callable class that returns a `Future`?

Yes, just make the call method async or have it return Future<T>. The instance can then be used with await.

Can I extend a callable class?

Yes, callable classes are regular classes; you can extend them and override the call method if needed.

Previous

dart typedef

Next

dart metadata

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.