Search code examples
f#immutabilityshadowing

immutable in F#


I know that variables in F# are immutable by default. But, for example in F# interactive:

  > let x = 4;;

val x : int = 4

> let x = 5;;

val x : int = 5

> x;;
val it : int = 5
> 

So, I assign 4 to x, then 5 to x and it's changing. Is it correct? Should it give some error or warning? Or I just don't understand how it works?


Solution

  • When you write let x = 3, you are binding the identifier x to the value 3. If you do that a second time in the same scope, you are declaring a new identifier that hides the previous one since it has the same name.

    Mutating a value in F# is done via the destructive update operator, <-. This will fail for immutable values, i.e.:

    > let x = 3;;
    
    val x : int = 3
    
    > x <- 5;;
    
      x <- 5;;
      ^^^^^^
    
    stdin(2,1): error FS0027: This value is not mutable
    

    To declare a mutable variable, add mutable after let:

    let mutable x = 5;;
    
    val mutable x : int = 5
    
    > x <- 6;;
    val it : unit = ()
    > x;;
    val it : int = 6
    

    But what's the difference between the two, you might ask? An example may be enough:

    let i = 0;
    while i < 10 do
        let i = i + 1
        ()
    

    Despite the appearances, this is an infinite loop. The i declared inside the loop is a different i that hides the outer one. The outer one is immutable, so it always keeps its value 0 and the loop never ends. The correct way to write this is with a mutable variable:

    let mutable i = 0;
    while i < 10 do
        i <- i + 1
        ()