Learning Rust #2: Option & Result
Tags: rust, learning
Published: 2021-03-19 09:00:47

---
title: Learning Rust #2: Option & Result
published: true
description: This month, I want to talk about something that made me struggle a lot and caused (and still causes) my code writing to slow down considerably - Option and Result types and how I constantly run into issues with them.
tags: rust, learning
series: Learning Rust
canonical_url: https://hamatti.org/posts/learning-rust-2-option-result/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hejx5fj66eqt6a3i8rf5.png
---

_Last December I finally started learning Rust and last month I built and published my first app with Rust: [235](https://hamatti.org/posts/introducing-235/). Learning Rust is my new monthly blog series that is definitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way._

Last month I started this series by talking about something I really enjoyed: pattern matching. And while writing and after sharing that post, I did further refactoring on the codebase based on ideas and suggestions by the community. Special thanks to Juho F. for helping out!

This month, I want to talk about something that made me struggle a lot and caused (and still causes) my code writing to slow down considerably: `Option` and `Result` types and how I constantly run into issues with them.

Coming from Python and Javascript development, I'm used to values being most often just values (or `null`). I can call a function and immediately continue with the return value.

In Rust, things are done a bit differently. You can still write functions that take an input and return a value but in many cases, functions return an [`Option`](https://doc.rust-lang.org/std/option/) or [`Result`](https://doc.rust-lang.org/std/result/) that are kind of wrappers around the actual values. The reason for this is to add safety over different kind of errors and missing values.

## What is an `Option`?

`Option` is a type that is always either `Some` or `None`.

```rust
fn divide(numerator: f64, denominator: f64) -> Option<f64> {
    if denominator == 0.0 {
        None
    } else {
        Some(numerator / denominator)
    }
}
```

The above example is from [Rust Option's documentation](https://doc.rust-lang.org/std/option/) and is a good example of `Option`'s usefulness: there's no defined value for dividing with zero so it returns `None`. For all other inputs, it returns `Some(value)` where the actual result of the division is wrapped inside a `Some` type.

For me, it's easy to understand why it's implemented that way and I agree that it's a good way to make the code more explicit about the ways you treat different end cases. But it can be so frustrating especially when learning programming.

There are a couple of ways to get the value from `Option`s:

```rust
// Pattern match to retrieve the value
match result {
    // The division was valid
    Some(x) => println!("Result: {}", x),
    // The division was invalid
    None    => println!("Cannot divide by 0"),
}
```

Continuing from previous example and [my previous blog post](https://dev.to/hamatti/learning-rust-1-pattern-matching-mia) on the topic, pattern matching gives a clean interface for continuing with the data. I find this most useful when it's the end use case for the result.

```rust
games.into_iter().for_each(|game| match game {
  Some(game) => print_game(&game, use_colors),
  None => (),
});
```

In [235](https://github.com/Hamatti/nhl-235), I use it for example to print games that have been parsed correctly and just ignore the ones that were not. Ignoring them is not a very good way in the long run but in this case, it's been good enough.

Other way is to `unwrap` the `Option`. The way `unwrap` method works is that it returns the value if `Option` is `Some` and panics if it's `None`. So when using plain `unwrap`, you need to figure out the error handling throughout.

There are also other variants of `unwrap`. You can `unwrap_or` which takes a default value that it returns when `Option` is `None`. And `unwrap_or_else` which functions like the previous but takes a function as a parameter and then runs that on the case of `None`. Or you can rely on the type defaults by running `unwrap_or_default` if all you need is a type default.

But there's still more! For added variety, there's the `?` operator. If the `Option` it's used on is a `Some`, it will return the value. If it's a `None`, it will instead return out from the function it's called in and return `None`. So to be able to use `?` operator, you need to make your function's return type an `Option`.

To create an `Option` yourself, you need to use either `Some(value)` or `None` when assigning to a variable or as a return value from a function.

## What's a `Result` then?

The other "dual type" (I don't know what to call it) in Rust is [`Result`](https://doc.rust-lang.org/rust-by-example/error/option_unwrap/question_mark.html). Similar to `Option` above, `Result` can be one of two things: it's either an `Ok` or an `Error`. To my understanding so far, `Ok` basically functions the same than `Some` that it just contains the value. `Error` is more complex than `None` in that it will carry the error out from the function so it can be taken care of elsewhere.

Same kind of pattern matching can be used to deal with `Results` than with `Options`:

```rust
match fetch_games() {
  Ok(scores) => {
    let parsed_games = parse_games(scores);
    print_games(parsed_games, use_colors);
  }
  Err(err) => println!("{:?}", err),
};
```

In [235](https://github.com/Hamatti/nhl-235), on the top level, I use above pattern match after fetching the scores from the API. If anything happens with the network request, the application will print out the error. One of the tasks on my todo list is to build a bit more user-friendly output depending on the different cases rather than just printing out raw Rust errors. I haven't figured out yet how to deal with errors in Rust in more detail yet though – once I do, I'll write a blog post in this series about it.

Like with `Option`, `unwrap` and `?` also work for `Result`.

## So why do I struggle?

As I've been writing this blog post, everything seems so clear and straight-forward to me. Still, when actually writing the code, I stumble a lot. As I mentioned earlier, I come from Python and Javascript where none of this is used.

One thing I've noticed to struggle is that I write some code, calling a function from standard library or some external library and forget it's using either `Option` or `Result`. Or I forget which one had which internals and thus, I'm still in a phase with Rust where I need to check so many things from the documentation all the time.

It also feels like you need to take so many more things into consideration. If you want to use `?`, you also need to change the way your function is defined and how the caller works and sometimes that can go on for a few levels. So my inexperience with the language leads to plenty of constantly making messy changes all around and occasionally ending up in a dead end I can't dig myself out of and I end up starting over.

And while I know it's mostly about getting used to a different system, I sometimes feel so dumb when I struggle with making the code not take into account all different ways it can crash (which is a big reason `Option` and `Result` are built the way they are).

## What's up with 235?

I've been using 235 myself daily since the first developmental version and I'm loving it. It's the one piece of software I'm most proud of and it's been answering my needs very well – and from what I've heard of from others, their needs as well.

235 is about to hit version 1.0. I'm getting confident that I've taken care of most of the major bugs conserning the basic usage and that gives me confidence in incrementing the version to 1.0.

Two things still need to be taken care before that and I'll hopefully get them done early March once I get a couple of lectures and talks out of my plate. First thing is to fix a [bug that has a slight chance to appear during the playoffs](https://github.com/Hamatti/nhl-235/issues/22). Second one is to make the [error handling bit better and provide more user-friendly outputs when things go wrong](https://github.com/Hamatti/nhl-235/issues/16).

## If I wanna learn Rust, where should I go?

Like I said, don't take these posts as gospel or tutorial. If you wanna learn Rust, my recommendation as a starting point (and one I started with) is [Rust Book](https://doc.rust-lang.org/book/) and with it, [Rust by Example](https://doc.rust-lang.org/rust-by-example/index.html). Also, joining your local Rust communities and being active in Twitter by following [@rustlang](https://twitter.com/rustlang) and taking part in discussions with #rustlang.