The if-let (RFC) was initially proposed August 16, 2014. A brief description from the RFC:

Introduce a new if let PAT = EXPR { BODY } construct. This allows for refutable pattern matching without the syntactic and semantic overhead of a full match, and without the corresponding extra rightward drift. Informally this is known as an “if-let statement”.

This pattern/expression bring syntactic sugar to awkward match expressions such as:

// Make `optional` of type `Option<i32>`
let optional = Some(7);

match optional {
    Some(i) => {
        println!("This is a really long string and `{:?}`", i);
        // ^ Needed 2 indentations just so we could destructure
        // `i` from the option.
    },
    _ => {},
    // ^ Required because `match` is exhaustive. Doesn't it seem
    // like wasted space?
};

Instead, (here continuing to reference the Rust by Example linked above) we could do:

if let Some(i) = letter {
    println!("Matched {:?}!", i);
} else {
    println!("Didn't match a number. Let's go with a letter!");
}

From the RFC, we get the generalized pattern:

if let PAT = EXPR { BODY }

Generalizing to DTR, we can do something like this:

{ instruction: evaluate, input: (SOME_EXPRESSION), assign: SOME_EXPRESSION_RESULT, scope: 0 }
{ instruction: evaluate, input: (try_assign, SOME_EXPRESSION_RESULT, SOME_TYPE), assign: SUCCESSFUL_ASSIGN_RESULT, scope: 0 }
{ instruction: jump, input: (SUCCESSFUL_ASSIGN_RESULT, 1), scope: 0 }
*** BODY at scope 1 ***
{ instruction: jump, input: (0), scope: 1 }

Let’s now handle that the specific example above and translate to DTR.

// [0] let Some(i) = letter
{ instruction: evaluate, input: (try_assign, Some(i), letter), assign: SUCCESSFUL_ASSIGN_RESULT, scope: 0 }
// [0] if let ..., scope = 1
{ instruction: jump, input: (SUCCESSFUL_ASSIGN_RESULT, 1), scope: 0 }
// [0] else, scope = 2
{ instruction: jump, input: (2), scope: 0 }
// [1] println!("Matched {:?}!", i);
{ instruction: print, input: ("\"Matched {:?}!\"", i), scope: 1}
// [1] scope = 0
{ instruction: jump, input: (0), scope: 1 }
// [2]  println!("Didn't match a number. Let's go with a letter!");
{ instruction: print, input: (\""Didn't match a number. Let's go with a letter!\""), scope: 2}
// [2] scope = 0
{ instruction: jump, input: (0), scope: 2 }

try_assign

In order to handle the if-let, we introduced a new valid method (first arg to the evaluate instruction). A try_assign is not something we expect to offer in the Digicus native IDE. However, it is helpful to represent the following concept from Rust:

An attempted assignment to a variable that may fail due to invalid pattern matching.

try_assign accepts two inputs:

  1. the left hand side of the conditional let application
  2. the right hand side

The result of this operation is the value indicated by the assign field of the instruction.