option 1.2.0

  • README.md
  • Installing
  • Versions
  • 52

Option

Build Status

The option typeclass inspired by scala's implementation and Haskell's Maybe monad. In more OOP languages it's been known to go by the name of the null object pattern. Option is a composable and more expressive alternative to things that may be null on absence of value. When used prolifically in a code base it means that you should never have to manually check for null again because this edge case will always be codified and enforced via the type system.

Speaking at a conference in 2009 Tony Hoare, the creator of the null reference apologized for it's creation, calling it his billion dollar mistake. In his own words, his introduction of null "... has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."

Examples

Nested Null Checking

The Option<T> type is all about taking null check riddled code like the following:

int compute(Foo foo) {
  if (foo == nul) {
    return null;
  }
  
  final bar = foo.getBar();
  if (bar == null) {
    return null;
  }
  
  final baz = bar.getBaz();
  if (baz == null) {
    return null;
  }
  
  return baz.compute();
}

With the much cleaner and easier to comprehend composition instead:

int compute(Option<Foo> optionalFoo) {
  return optionalFoo
    .flatMap((Foo foo) => foo.getBar())
    .flatMap((Bar bar) => bar.getBaz())
    .flatMap((Baz baz) => baz.compute());
}

Downcasting Back Down To Null Land

Unfortunately, not every library you use is going to be expecting Option<T> values. So we give you a means of "downcasting" your Option<T> values to their flat type equivelent or null

int compute(Option<Foo> optionalFoo) {
  final intOrNull = optionalFoo.map((Foo) => foo.getInt()).orNull();
  return expectsIntOrNull(intOrNull);
}

Sane Defaults On Null

Some times you want to unwrap the value contained within an Option<T> and if that inner value doesn't exist (it's a None<T>) you want to set it to a sane default value instead, you can use either Option#getOrDefault(T) or Option#getOrElse(T alt()).

Heres how you would default to the value zero on null.

int compute(Option<Foo> optionalFoo) {
  return optionalFoo
    .flatMap((Foo foo) => foo.getBar())
    .flatMap((Bar bar) => bar.getBaz())
    .flatMap((Baz baz) => baz.compute())
    .getOrDefault(0);
}

Heres how you would default to a lazily executed alternative computation on null.

int compute(Option<Foo> optionalFoo) {
  return optionalFoo
    .flatMap((Foo foo) => foo.getBar())
    .flatMap((Bar bar) => bar.getBaz())
    .flatMap((Baz baz) => baz.compute())
    .getOrElse(() => alternativeComputation(optionalFoo));
}

Anonymous Filtering/Validation

Some times you need to perform some filtering or validation on a value and you don't necessarily care exactly what part fails, just that it passes all filters or that it doesn't.

final emailRegex = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';

bool minLength(int length, String string) {
  return string.length >= length;
}

bool matchesRegex(RegExp regex, String string) {
  return regex.hasMatch(string));
}

Option<String> validateEmail(String email) {
  return new Option(email)
    .filter((email) => minLength(4, email))
    .filter((email) => matchesRegex(new RegExp(emailRegex), email))
}

Pattern Matching / Folding / Catamorphism

Some times you'll have an Option<T> value and you want just want to do one computation if it's empty and another if it's non empty with the contained value and return the result of either case. In the null checking world this would be facilitated via an "is null" check. However, instead we do a rough approximation of what other languages call pattern matching by using a technique that functional programmers call "Folding" or "Catamorphism". We supply the Option<T> value with two functions, one which will run in either case and we pass them to the Option#cata() method.

bool nonEmptyValidator(Option<String> input)  {
  return input.cata(
    ()  => false,
    (n) => n.length > 0
  );
}

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  option: "^1.2.0"

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:option/option.dart';
        
Version Uploaded Documentation Archive
1.2.0 Apr 23, 2016 Go to the documentation of option 1.2.0 Download option 1.2.0 archive
1.1.0 Aug 19, 2014 Go to the documentation of option 1.1.0 Download option 1.1.0 archive
1.0.2 Aug 17, 2014 Go to the documentation of option 1.0.2 Download option 1.0.2 archive
1.0.0 Aug 16, 2014 Go to the documentation of option 1.0.0 Download option 1.0.0 archive
0.3.3 May 4, 2013 Go to the documentation of option 0.3.3 Download option 0.3.3 archive
0.3.2 Apr 18, 2013 Go to the documentation of option 0.3.2 Download option 0.3.2 archive
0.3.1 Apr 13, 2013 Go to the documentation of option 0.3.1 Download option 0.3.1 archive
0.3.0 Apr 1, 2013 Go to the documentation of option 0.3.0 Download option 0.3.0 archive
0.2.3 Mar 17, 2013 Go to the documentation of option 0.2.3 Download option 0.2.3 archive
0.2.2 Mar 17, 2013 Go to the documentation of option 0.2.2 Download option 0.2.2 archive

All 13 versions...

Analysis

We analyzed this package on Apr 9, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.46.0
  • pana: 0.10.6

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
82 / 100
Health:
Code health derived from static analysis. [more]
36 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
0 / 100
Overall score:
Weighted score of the above. [more]
52
Learn more about scoring.

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:option/option.dart.

Suggestions

  • Maintain CHANGELOG.md.

    Changelog entries help clients to follow the progress in your code.

  • Fix analysis and formatting issues.

    Analysis or formatting checks reported 9 errors 6 hints.

    Strong-mode analysis of lib/src/none.dart failed with the following error:

    line: 53 col: 3
    Invalid override. The type of 'None.map' ('((T) → dynamic) → Option<dynamic>') isn't a subtype of 'Iterable<T>.map' ('<T₀>((T) → T₀) → Iterable<T₀>').

    Strong-mode analysis of lib/src/option.dart failed with the following error:

    line: 3 col: 16
    Inconsistent declarations of 'expand' are inherited from ((dynamic) → Option<dynamic>) → Option<dynamic>, <T₀>((T) → Iterable<T₀>) → Iterable<T₀>.

    Similar analysis of the following files failed:

    • lib/src/some.dart (error)
    • lib/option.dart (hint)
  • The description is too long.

    Search engines will display only the first part of the description. Try to keep it under 180 characters.

  • Maintain an example.

    None of the files in your example/ directory matches a known example patterns. Common file name patterns include: main.dart, example.dart or you could also use option.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
concepts >=0.1.0 <=1.0.0 0.2.0
either >=0.1.0 <0.2.0 0.1.8
Dev dependencies
unittest 0.4.7+1