`ref` vs. `mutable` assignment operator using F#
-
25-10-2019 - |
Question
Consider the following code:
let mutable a = 0.
let b = ref 0.
a <- // works
printfn "%A" a
4. + 8.
b := // does not work
printfn "%A" a
4. + 8.
b := ( // works
printfn "%A" a
4. + 8. )
Why does the ref assignment operator (:=) have a different behaviour than the mutable assignment operator (<-)?
Solution
Building on the other answers...
More elaborate expressions are allowed within assignments, so long as the final expression is one of several allowed forms. See section 6.4.9 of the spec. This allows complex assignments such as:
let x =
let rec gcd a = function
| 0 -> a
| b -> gcd b (a % b)
gcd 10 25
The compiler moves gcd
to a private member, but nesting it within the assignment allows for tighter scoping. Function arguments, on the other hand, are more restricted. They don't create a new scope (that I'm aware of) and you can't define functions, for example, as part of the expression.
OTHER TIPS
I can only give a partial answer.
:=
is defined in terms of <-
in FSharp.Core\prim-types.fs:
let (:=) x y = x.contents <- y
In your example
b := // does not work
printfn "%A" a
4. + 8.
printfn "%A" a
seems to be interpreted as y
, which cannot be assigned to the int ref cell (wrong type). By grouping the whole expression with ( ... )
, y
now also contains 4. + 8.
. Maybe the two operators behave differently, because <-
seems to be an intrinsic operator (i.e. part of the language, not the library).
:=
is a function (try (:=);; in FSI) which has a type : 'a ref -> 'a -> unit
So
b := // does not work
printfn "%A" a
4. + 8.
is being parsed as because of the infix call parsing rule:
(:=) b (printfn "%A" a)
4. + 8.
Which is invalid as par the (:=) function type. Other example:
let c = 10 +
11
12
c would be 12 here
Looks like a discrepancy in the indentation-sensitive parser rather than anything specifically to do with those operators.