module Let { 
 
  // FUNCTION SCOPED (LOCAL) VARIABLES 
 
  fn test1() { 
 
    // within a function, use let to declare a local variable and it's type 
    let x1 : int; 
 
    // the variable can be assigned an initial value 
    let x2 : int = 1; 
 
    // the type can be omitted if an initial value is provided.  the type of the 
    // variable will be the type of the initial value. 
    let x3 = 1;  // type of z is int 
  } 
 
  // LOCAL VARIABLE DESTRUCTURING 
 
  fn test2() { 
 
    // let can be used to "destructure" data structures 
    // • _ indicates match anything 
    // • ... indicates match rest (for sequences) 
    // • variable names indicate a new variable definition that will have the value at that position 
 
    // destructure an array and initialize new variables x and y 
    let [_, x, y, ...] = [1, 2, 3];           // x is 2, y is 3  
 
    // destruture a map and initialize a new variable x2 
    let {"b" : x2, "c" : y2} = {"a" : 1, "b" : 2, "c" : 3};       // x2 is 2, y2 is 3 
 
    // destructure a tuple and initialize a new variable x3 
    let (_, x3, y3, ...) = (1, 2, "3", 4, 5);       // x3 is 2, y3 is "3" 
 
    // destructure a vector and initialize a new variable x4 
    let #(x4, y4, _) = #(1, 2, 3);      // x4 is 1, y4 is "2" 
 
    // destructure nested structures 
    let {"a" : [x5, ...]} = {"a" : [1, 2]};  // x5 is 1 
 
    // using ...v will capture the remainder into a variable v 
    let [_, ...x6] = [1, 2, 3];   // x6 is [2, 3] 
 
    // accessing a value that does not exist will cause an exception 
    let {"a" : x7} = {"b" : 1};    // exception indicating key "a" was not found in map 
    let [_, _, x8] = [1];          // exception indicating array is wrong size 
  } 
 
  // THREAD LOCAL VARIABLES 
 
  // logger function used in example below 
  typedef Logger = fn(message : string) : void; 
 
  // use let at the module/project scope to define a thread-local variable. 
  // there are no global variables in this language.  thread local variables 
  // must have an initializer that is a constant expression. 
 
  // define a logger variable which holds a function that logs 
  let logger : Logger? = none;  
 
  fn test3() { 
    // log if logger present 
    if (logger) { 
      logger!("hello");   // does not execute 
    } 
 
    // update logger variable to have a logging function 
    logger = fn::Logger(message) => print(message); 
 
    // log if logger present 
    if (logger) { 
      logger!("hello");   // prints hello 
    } 
  } 
 
  // TYPE SCOPED THREAD LOCAL VARIABLES  
 
  // use let with a type name to define a thread-local variable 
  // that is scoped to the type. 
 
  struct Node {} 
 
  let Node.node_count = 0; 
 
  fn test4() { 
    Node.node_count += 1; 
  } 
   
}