Let Binding
A "let binding", in other languages, might be called a "variable declaration". let
binds values to names. They can be seen and referenced by code that comes after them.
RElet greeting = "hello!";
let score = 10;
let newScore = 10 + score;
Block Scope
Bindings can be scoped through {}
.
RElet message = {
let part1 = "hello";
let part2 = "world";
part1 ++ " " ++ part2
};
/* `part1` and `part2` not accessible here! */
The value of the last line of a scope is implicitly returned.
Design Decisions
Reason's if
, while
and functions all use the same block scoping. The code below works not because of some special "if scope"; but simply because it's the same scope syntax and feature you just saw:
REif (displayGreeting) {
let message = "Enjoying the docs so far?";
print_endline(message)
};
/* `message` not accessible here! */
Bindings Are Immutable
Reason let bindings are "immutable", aka "cannot change/vary". This helps Reason's type system to deduce and optimize much more than other languages (and in turn, help you more).
Binding Shadowing
The above restriction might sound unpractical at first. How are would you change a value then? Usually, 2 ways:
The first is to realize that many times, what you want isn't to mutate a variable's value. For example, in JavaScript:
JSvar result = 0;
result = calculate(result);
result = calculateSomeMore(result);
What you're really doing is just to name intermediate steps. You didn't need to mutate result
at all! You could have just written this:
JSvar result1 = 0;
var result2 = calculate(result1);
var result3 = calculateSomeMore(result2);
In Reason, this obviously works too:
RElet result1 = 0;
let result2 = calculate(result2);
let result3 = calculateSomeMore(result2);
Anyway, in Reason, we support let binding "shadowing". So you can write this too:
RElet result = 0;
let result = calculate(result);
let result = calculateSomeMore(result);
As a matter of fact, even this is fine:
RElet result = "hello";
Js.log(result); // prints "hello"
let result = 1;
Js.log(result); // prints 1
The binding you refer to is whatever's the closest upward. No mutation here! If you need real mutation, e.g. passing a value around, have it modified by many pieces of code, we provide a slightly heavier mutation feature.