Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Option type to Dart #10422

Closed
DartBot opened this issue May 3, 2013 · 7 comments
Closed

Add Option type to Dart #10422

DartBot opened this issue May 3, 2013 · 7 comments
Assignees
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). closed-not-planned Closed as we don't intend to take action on the reported issue P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@DartBot
Copy link

DartBot commented May 3, 2013

This issue was originally filed by bordole...@gmail.com


I think it would be very useful to add an Option type (http://en.wikipedia.org/wiki/Option_type) to dart, particularly for when dealing with collections and maps, and when methods on any object are not guaranteed to return a non-null result [*].

For instance, the Map operator [] currently returns null if the key is not present. This forces users of Map to write fairly verbose error checking and is bug prone.

Example:

main() {
  Map<String, String> map = new Map();
  String s = map["key"];
  print(s.endsWith("example")); // noSuchMethodException
}

To fix this code, you need to remember to add null checks throughout your code and the compiler does not give any warnings of the potential bug.

an alternative is to instead return an Option type and call the method map:

main() {
  Map<String, String> map = new Map();
  Option<String> opt = map["key"];
  opt.map((String s) => print(s.endsWith("example"))); // Only called if s is non null
}

In addition, many of the Iterable methods currently throw RangeError or StateError and could be changed to instead return Option. This is useful since unchecked exceptions typically are not handled by programmers and can be tricky to debug.

Example
 
main() {
  Iterable<String> itr = [];
  String item = itr.elementAt(2); // RangeError, need to remember to add exception handling
  print(item);
}

The alternative with the Option type is:

main() {
  Iterable<String> itr = [];
  Option<String> opt = itr.elementAt(2); // Returns None since the element does not exist
  opt.map((String item) => print(item)); // Does nothing
  print(opt.orElse("default")); // prints default
}

[*] I think this is a different from the proposal in https://code.google.com/p/dart/issues/detail?id=22 for non-nullable types.

@madsager
Copy link
Contributor

madsager commented May 6, 2013

Added Area-Language, Triaged labels.

@DartBot
Copy link
Author

DartBot commented May 8, 2013

This comment was originally written by bord...@gmail.com


If you decided to implement this, I'd recommend making Option<T> implement Iterable<T> and more tightly defining the return types of the methods that return Iterable to return Option<T>. I find the easiest way for users to reason about option is to present it as the an Iterable that contain 1 or 0 elements.

@DartBot
Copy link
Author

DartBot commented Jul 16, 2013

This comment was originally written by mario.plon...@gmail.com


I'm hoping opinions are allowed here: I really hope this "feature" as it is described doesn't make it into Dart, or at least get their own Map and List classes. Why? Because it actually makes code more verbose, without any additional benefit. If I'm just getting something wrong here, please correct me (mail is fine too).

I've tried to write code as I would do it two different ways, once with Dart as it is, and once with a hypothetical option type, using the examples and descriptions above.

// not really that much of a difference
//////
map["key"].map((String s) => print(s.endsWith("example"));
// VS
if(map["key"]!=null) print(map["key"].endsWith("example"));

// current way is even better? key presses in dart editor (without shift): 60 : 66
//////
itr.elementAt(2)
  ..map((s) => print(s))
  ..orElse("default");
// VS
if(itr.length > 2)
  print(itr.elementAt(2));
else
  print("default");

So, there isn't really much difference in "coding speed".
But what if I actually WANT to throw an error if an element doesn't exist? This use-case isn't described above, but I'd imagine it would look similar to this:

map["key"].doSomething();
// VS
map["key"]
  ..map((o) => o.doSomething());
  ..orThrow("'key' doesn't exist in map");

That's a lot of additional code, compared to previous use-cases.

@DartBot
Copy link
Author

DartBot commented Jul 16, 2013

This comment was originally written by mario.pl...@gmail.com


Why don't you just use a wrapper, if this behaviour is needed?

class Option<T> {
  
  T _val;
  
  Option(T v) {
    this._val = v;
  }
  
  void run(void fn(T param), [T defaultValue]) {
    T realVal = this._val;
    if(realVal==null && defaultValue!=null) realVal = defaultValue;
    if(realVal!=null) {
      fn(realVal);
    }
  }
  
}

class OptionList<T> extends ListBase<T> {
  
  List<T> _list;
  
  OptionList() {
    this._list = [];
  }
  
  OptionList.fromList(List<T> l) {
    this._list = new List.from(l);
  }
  
  Option<T> operator[](int index) => elementAt(index);
  
  Option<T> elementAt(int index) {
    if(index < this._list.length) {
      return new Option<T>(this._list[index]);
    }
    return new Option<T>(null);
  }
  
}

void main() {
  OptionList<String> l = new OptionList.fromList(["test1", "test2"]);
  l[0].run((s) => print(s), "element not found");
  l[1].run((s) => print(s), "element not found");
  l[2].run((s) => print(s), "element not found");
}

@DartBot
Copy link
Author

DartBot commented Aug 20, 2013

This comment was originally written by kurisu....@gmail.com


@mario, the use case isn't as much "speed of coding." It's mostly about correctness. Nullable types have been considered by most of the PLT community I know (and plenty of programmers in the Industry too!) as the biggest mistake in computing, because it makes everything so much more error prone — programmers are lazy ;)

When you can't have nulls creeping throughout all of your code base, you can not possibly have NullPointerException, and you're forced to be remembered that you're dealing with a computation that might fail, and handle the errors accordingly. When any type can also be null, someone might change something in an library you're using, and you will only realise things broke when you start getting random NullPointerExceptions far down the road where they've actually happened!

@gbracha
Copy link
Contributor

gbracha commented Aug 25, 2014

Set owner to @gbracha.
Added Accepted label.

@DartBot DartBot added Type-Defect area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). labels Aug 25, 2014
@kevmoo kevmoo added P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) and removed accepted labels Feb 29, 2016
@munificent
Copy link
Member

As others have noted, you can definitely define your own Option class at the library level, and there are a number of third party ones floating around the ecosystem.

We don't currently have any plans to bake an option type into the core libraries. Instead, we're going to pursue supporting non-nullable types directly (#22). If that doesn't pan out, we may revisit this. But, until then, I'm going to close this as not planned.

@munificent munificent added the closed-not-planned Closed as we don't intend to take action on the reported issue label Dec 16, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). closed-not-planned Closed as we don't intend to take action on the reported issue P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

5 participants