Why is Rust’s .expect() called expect? [closed]

Summary:

No explicit reason for the name is given. However, it is incredibly likely the name comes from the world of parsers, where one “expects” to see a particular token (else the compilation fails).

Within rustc, the use of expect-like functions long predate use within Option. These are functions like expect(p, token::SEMI) to expect to parse a semicolon and expect_word(p, "let") to expect to parse the let keyword. If the expectation isn’t met, compilation fails with an error message.

Eventually a utility function was added within the compiler that would expect not a specific token or string, but that a given Option contained a value (else, fail compilation with the given error message). Over time this was moved to the Option struct itself, where it remains today.

Personally, I don’t find it unusual at all. It’s just another verb you can do to the object, like unwrapping or taking or mapping its value. Expecting a value (else, fail) from your Option seems quite natural.


History:

The oldest commit of note is the following:

https://github.com/rust-lang/rust/commit/b06dc884e57644a0c7e9c5391af9e0392e5f49ac

Which adds this function within the compiler:

fn expect<T: copy>(sess: session, opt: option<T>, msg: fn() -> str) -> T {
    alt opt {
       some(t) { t }
       none { sess.bug(msg()); }
    }
}

As far as I can tell, this is the first function named “expect” that deals with inspecting an Option. Observe in particular this example use-case within the commit (which was implementing support for class methods!):

#debug("looking up %? : %?", def, class_doc);
let the_field = expect(tcx.sess,
    decoder::maybe_find_item(def.node, class_doc),
    {|| #fmt("get_field_type: in class %?, field ID %? not found",
             class_id, def)});

If the result of decoder::maybe_find_item is None, compilation will fail with the given error.

I encourage you to look at the parser code in this commit – there is extensive use of other expect-esque functions: e.g., expect(p, token::RPAREN) and expect_word(p, "let"). The name of this new function is almost obvious in this environment.

Eventually, the utility of this function was extracted and placed within Option itself:

https://github.com/rust-lang/rust/commit/e000d1db0ab047b8d2949de4ab221718905ce3b1

Which looked like:

pure fn expect<T: copy>(opt: option<T>, reason: str) -> T {
    #[doc = "
    Gets the value out of an option, printing a specified message on failure
    # Failure
    Fails if the value equals `none`
    "];
    alt opt { some(x) { x } none { fail reason; } }
}

It’s worth noting that sometime later, there was eventually an (additional) function named unwrap_expect added in:

https://github.com/rust-lang/rust/commit/be3a71a1aa36173ce2cd521f811d8010029aa46f

pure fn unwrap_expect<T>(-opt: option<T>, reason: ~str) -> T {
    //! As unwrap, but with a specified failure message.
    if opt.is_none() { fail reason; }
    unwrap(opt)
}

Over time these were both subsumed by an Expect trait, which Option implemented:

https://github.com/rust-lang/rust/commit/0d8f5fa618da00653897be2050980c800389be82

/// Extension trait for the `Option` type to add an `expect` method

// FIXME(#14008) should this trait even exist?
pub trait Expect<T> {
    /// Unwraps an option, yielding the content of a `Some`
    ///
    /// # Failure
    ///
    /// Fails if the value is a `None` with a custom failure message provided by
    /// `msg`.
    fn expect<M: Any + Send>(self, m: M) -> T;
}

Spoiler for that TODO: that trait no longer exists. It was removed shortly after per:

https://github.com/rust-lang/rust/issues/14008.

More or less this is where we are at today.

I think the most likely conclusion is that the use of expect as a meaningful function name long predates its use in Option. Given it says what it does (expect a value or fail) there is little reason to break the pattern.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)