Twofold

Twofold is a small utility for representing values that can have one of two outcomes — commonly failure or success.

It is designed to be:

  • Simple
  • Explicit
  • Easy to read
  • Friendly for real-world Dart and Flutter apps

No special programming style or background is required.


Why Twofold?

In many applications, operations can:

  • succeed with a value
  • fail with a reason

Twofold<L, R> lets you model this clearly without relying on exceptions or nullable values.


Installation

dependencies:
  twofold: ^0.1.0
import 'package:twofold/twofold.dart';

Basic usage

Creating values

final success = right<String, int>(42);
final failure = left<String, int>('Something went wrong');

Checking state

if (result.isRight) {
print('Operation succeeded');
}
if (result.isLeft) {
  print('Operation failed');
}

final message = result.fold(
  (error) => 'Failed: $error',
  (value) => 'Success: $value',
);

Side effects

result.when(
  (error) => log(error),
  (value) => save(value),
);

Transforming values

map

final doubled = right<String, int>(2)
    .map((v) => v * 2);

mapLeft

final formattedError = left<int, String>(404)
    .mapLeft((code) => 'Error $code');

flatMap (chaining)

Twofold<String, int> parse(String value) {
  final parsed = int.tryParse(value);
  return parsed != null
      ? right(parsed)
      : left('Invalid number');
}

final result = right<String, String>('10')
    .flatMap(parse);

Fallback values

final value = result.getOrElse(0);
final value = result.getOrElseGet(() => expensiveFallback());

Utility helpers

print(result.toStringValue());
final isSame = a.isEqualTo(b);
final hash = result.hashValue;

Important note

A Twofold should contain exactly one value:

  • either a left value
  • or a right value

Creating a value where both are null is considered invalid and will throw at runtime when accessed.

This will be enforced more strictly in future versions.

Libraries

twofold