Is using an enum constructor worth a lazy evaluation?

This is a simplified version of an example that triggers clippy's unnecessary_lazy_evaluations lint:

#![warn(clippy::unnecessary_lazy_evaluations)]

pub enum Foo {
    A(String),
    B(Box<Foo>),
}

fn bar(s: &str) -> Option<Foo> {
    if s.len() < 42 {
        Some(Foo::B(Box::new(Foo::A("hello".to_owned()))))
    } else {
        None
    }
}


pub fn foo(s: String) -> Foo {
    bar(&s).unwrap_or_else(|| Foo::A(s))
}

It suggests that the last line be replaced with bar(&s).unwrap_or(Foo::A(s)). Is that a good idea? Assuming that everything except bar gets inlined and optimized, does building a value using an enum constructor count as work that ought to be delayed in the case that bar returns Some(...)? I tried looking at the MIR for this in the playground but it doesn't look like it's being optimized.

Using an enum constructor is basically free, so yes replace it with unwrap_or

1 Like

Isn't it a memcpy? In my real example it's also in an Ok so it seems like you would want to resolve both of those at the same time.

Yes it's a memcpy, but so are moves (like moving the s: String into the closure). Keep in mind that using a closure is constructing an anonymous type and moving things inside.

You can read more about closures on by blog

1 Like

Is a closure actually constructed though? I would expect this code to actually be compiled to a match, because unwrap_or_else is being applied to a closure that only exists once in the code, so monomorphization will kick in and this specialized unwrap_or_else will almost certainly be inlined.

The closure definitely gets constructed, however there is something else going here.
I just checked godbot and got results I wasn't expecting Compiler Explorer. It looks like LLVM can't elide the drop glue for Foo! This is because allocating memory using Box::new and to_owned could in theory panic, and so then the drop glue would be run. Then it can't figure out that Foo::A is the only variant constructed.

Depending on if this matters to you, I would silence clippy and make a comment with this godbolt link. Using a closure doesn't construct Foo, until we can prove that panics don't happen so it's all good.

3 Likes