Let...else and the Samuel L Jackson operator

Let...else and the Samuel L Jackson operator

·

3 min read

Good day, everyone! Here's some useful Rust for you, with situational usage. This is all just from my experience and ended up being in my toolbox. There might be things that are silly and you'll feel the need to correct me, and that's fine! We live and learn.

let...else is a literal gamechanger

I found out about this very late, but it's one of those things that I don't know how I lived without. Whenever you have a deconstructable object that you want to check for one variant, but you want your flow to just stop if it's not there -- let...else is your friend!

For example, I need my function to get me the player object if it's present, and from it get an item it's holding, but if either of those fails -- i don't want this function to do anything else. Here's the code without let...else:

fn player_dependent_system(player_query: Query<&Player>) {
  if let Some(player) = query.get_single() {
    if let Some(item) = player.holding {
      // do something here
    }
  }
}

And now here's with let...else:

fn player_dependent_system(player_query: Query<&Player>) {
  let Some(player) = query.get_single() else { return };
  let Some(item) = player.holding else { return };
  // do something
}

Much cleaner. rust_fmt likes putting the else { return; }; on three separate lines, which is a killjoy for brevity but still a win for low scope creep.

The "whatever the .. else" notation keeps code flowing

Here's a semi-realistic example I had a few days ago that underlined the value of what I'm calling the Samuel L. Jackson operator because of how little it gives a ...

Imagine we had two enums, something like:

enum Engine {
    Loading,
    Inside { state: Game, tag: String, window: Window, config: Option<Path> }
}

enum Game {
    Loading,
    Scene { name: String, act: u32, width: u32, height: u32,  },
}

Somewhere in main, we construct EngineState:

fn main() {
    // some more code here defining engine_window
    let state = Engine::Inside { 
        state: Game::Scene { 
            name: "Scene1".to_string(), 
            act: 1, 
            width: 32, 
            height: 32 
        }, 
        tag: "Main".to_string(),
        window: engine_window,
        config: None,
    };
}

Now someone asks us to print the name of the scene within the game state that the engine is in, if any. It seems like a long way to go to match all that, even with let...else it isn't pretty because of all the unused variables along the way:

fn print_scene_name(engine_state: &EngineState) {
    let Engine::Inside { scene, tag: _, window: _, config: _ } = engine_state else { return };
    let Game::Scene { name, act: _, width: _, height: _ } = scene else { return };
    println!("{}", name);    
}

We could, of course, make it into a single line, embed the Scene inside the scene field directly, but that ends up being quite unwieldy too. The answer is the Samuel operator, which "resolves" everything you don't care about. It now looks clean even in one line:

fn print_scene_name(engine_state: &EngineState) {
    if let Engine::Inside { state: Game::Scene { name, .. }, .. } = engine_state {
        println!("{:?}", name);
    }
}

Re-solved. -- a picture of Samuel L. Jackson

Re-solved.

This time it was more about being succinct. Next time, we'll be looking at two cool patterns that you might want to learn -- and might have actually attempted to write yourself if you've come from C++. Enjoy!