Errors in Dart

In Dart, error handling is typically done using exceptions, which is different from Go’s approach. However, we can create a similar pattern using a custom Result class to mimic Go’s multiple return values for errors.

import 'dart:io';

// A custom Result class to mimic Go's multiple return values
class Result<T> {
  final T? value;
  final String? error;

  Result(this.value, this.error);
}

// By convention, we return a Result object instead of throwing exceptions
Result<int> f(int arg) {
  if (arg == 42) {
    // Return an error result
    return Result(null, "can't work with 42");
  }
  // Return a successful result
  return Result(arg + 3, null);
}

// Sentinel errors as constants
const String errOutOfTea = "no more tea available";
const String errPower = "can't boil water";

Result<void> makeTea(int arg) {
  if (arg == 2) {
    return Result(null, errOutOfTea);
  } else if (arg == 4) {
    // We can add context to errors by prefixing the message
    return Result(null, "making tea: $errPower");
  }
  return Result(null, null);
}

void main() {
  for (var i in [7, 42]) {
    // It's common to use an inline error check
    var result = f(i);
    if (result.error != null) {
      print('f failed: ${result.error}');
    } else {
      print('f worked: ${result.value}');
    }
  }

  for (var i = 0; i < 5; i++) {
    var result = makeTea(i);
    if (result.error != null) {
      // In Dart, we use string comparison instead of errors.Is
      if (result.error == errOutOfTea) {
        print('We should buy new tea!');
      } else if (result.error!.contains(errPower)) {
        print('Now it is dark.');
      } else {
        print('unknown error: ${result.error}');
      }
      continue;
    }
    print('Tea is ready!');
  }
}

To run this Dart program, save it as errors.dart and use the following command:

$ dart run errors.dart
f worked: 10
f failed: can't work with 42
Tea is ready!
Tea is ready!
We should buy new tea!
Tea is ready!
Now it is dark.

In this Dart example, we’ve created a Result class to mimic Go’s multiple return values for error handling. The f and makeTea functions return Result objects instead of throwing exceptions.

We use string constants errOutOfTea and errPower to represent sentinel errors. In the makeTea function, we demonstrate how to add context to errors by prefixing the error message.

In the main function, we show how to check for errors and handle them. Instead of errors.Is, we use string comparison or the contains method to check for specific errors.

This approach provides a way to handle errors explicitly in Dart, similar to Go’s error handling pattern. However, it’s important to note that this is not the idiomatic way to handle errors in Dart, which typically uses exceptions for error handling.