dfp 0.4.0 copy "dfp: ^0.4.0" to clipboard
dfp: ^0.4.0 copied to clipboard

A library for typed functional programming in Dart, inspired by Rust.

dfp #

dfp is a library for typed functional programming in Dart, inspired by Rust.

Result #

Result is a type that represents either success (Ok) or failure (Err).

For example, you can use Result with dio:

import 'package:dfp/dfp.dart';

...

Future<Result<User, String>> fetchUser() async {
  final response =
      await asyncTryCatch<Response<Map<String, dynamic>>, DioError>(
    dio.get(Urls.account),
  );

  return response
      .map((r) => UserDto.fromJson(r.data!))
      .map((value) => value.toModel())
      .mapErr((error) {
    if (error.response?.statusCode == 401) return 'Unauthorized error';

    return 'Another error';
  });
}
copied to clipboard

In this case, we have converted the successful response to a DTO model, and then we have converted it to a domain model. Also we have converted the error value (if we got it) from DioError to String.

We can use the result value with the provided methods, such as ifOkElse:

  // somewhere in BLoC
  fetchUser: (_) async {
    emit(UserState.loading());

    final result = await fetchUser();
    result.ifOkElse((user) {
      emit(UserState.loaded(user));
    }, (error) {
      emit(UserState.error(error));
    });
  },
copied to clipboard

If we don't care about the error, we can use the result.ok value, which also provides many useful methods. For example:

  Future<Option<User>> fetchUser() async {
    final response =
        await asyncTryCatch<Response<Map<String, dynamic>>, DioError>(
      _httpClient.get(Urls.account),
    );

    return response
        .map((r) => UserDto.fromJson(r.data!))
        .map((value) => value.toModel())
        .ok;
  }

  ...

  // somewhere in BLoC
  fetchUser: (_) async {
    emit(UserState.loading());

    final result = await fetchUser();
    result.ifSomeElse((user) {
      emit(UserState.loaded(user));
    }, () {
      emit(UserState.error());
    });
  },
copied to clipboard

Instead of result.ifOkElse we can use result.ifOk, result.ifErr or result.when:

result.ifOk((user) {
  emit(UserState.loaded(user));
})
...
result.ifErr(error) {
  emit(UserState.error(error));
});
...
result.when(
  ok: (user) => emit(UserState.loaded(user)),
  err: (error) => emit(UserState.error(error)),
);
copied to clipboard

Option #

Option<A> is a container for an optional value of type A. If the value of type A is present, the Option<A> is an instance of Some<A>, containing the present value of type A. If the value is absent, the Option<A> is an instance of None.

An option could be looked at as a collection or foldable structure with either one or zero elements. Another way to look at Option is: it represents the effect of a possibly failing computation.

The Option class also provides a number of useful methods such as map, ifSome, ifNone, ifSomeElse, and when. These methods work in the same way as the map, ..., when methods of the Result.

You can create an Option object from a nullable value using the Option.fromNullable constructor or the fromNullable function, like this:

final str = Option.fromNullable(stdin.readLineSync());
final number = Option.flatten(
  str.map((value) => Option.fromNullable(double.tryParse(value))),
);
final fixed = number
    .map(sin)
    .map((value) => value * 2)
    .map((value) => value.abs().toStringAsFixed(2));
print(fixed.toNullable());
copied to clipboard

toNullable method conversely allows you to turn an Option object into a value of the nullable type.

You can convert an Option to a Result using the okOr method:

final n = Option.fromNullable(double.tryParse('value'));
final result = n.okOr('Not a number'); // Result<double, String>

copied to clipboard

Or you can get the contained Option value using the getOrElse method. It returns the contained Some value or a provided fallback for None:

final n = Option.fromNullable(double.tryParse('value'));
print(sin(n.getOrElse(0)));
copied to clipboard

functions #

dft also provides several functions that can be used to get Option and Result objects:

final value = 5;
final even = option(value.isEven, value);

final nullable = fromNullable(double.tryParse('value'));

final number =
    tryCatch<double, FormatException>(() => double.parse('source'));

final result = asyncTryCatch<Response<Map<String, dynamic>>, DioError>(() =>
    dio.get(Urls.account));
copied to clipboard
0
likes
150
points
36
downloads

Publisher

unverified uploader

Weekly Downloads

2024.08.07 - 2025.02.19

A library for typed functional programming in Dart, inspired by Rust.

Repository (GitHub)

Documentation

API reference

License

MIT (license)

More

Packages that depend on dfp