Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'mutable' in type definition

Tags:

f#

Why is disabled types like

type t = A of int | B of string * mutable int

while such types are allowed:

type t = A of int | B of string * int ref
like image 793
ssp Avatar asked Dec 03 '22 13:12

ssp


2 Answers

The question is, how would you modify the value of a mutable element of discriminated union case? For ref types, this is quite easy, because ref is a reference cell (a record actually) which contains the mutable value:

match tval with
| B(str, refNum) -> refNum := 4

We extract the reference cell and assign it to a new symbol (or a new variable) refNum. Then we modify the value inside the ref cell, which also modifies tval, because the two references to the cell (from discriminated union case and from refNum variable) are aliased.

On the other hand, when you write let mutable n = 0, you're creating a variable, which can be directly mutated, but there is no cell holding the mutable value - the variable n is directly mutable. This shows the difference:

let mutable a = 10
let mutable b = a
b <- 5   // a = 10, b = 5

let a = ref 10
let b = a
b := 5   // a = 5, b = 5 (because of aliasing!)

So, to answer your question - there is no way to directly refer to the value stored inside the discriminated union case. You can only extract it using pattern matching, but that copies the value to a new variable. This means that there isn't any way you could modify the mutable value.

EDIT To demonstrate limitations of mutable values in F#, here is one more example - you cannot capture mutable values inside a closure:

let foo() = 
  let mutable n = 0
  (fun () -> n <- n + 1; n) // error FS0407

I think the reason is same as with discriminated union cases (even though it's not as obvious in this case). The compiler needs to copy the variable - it is stored as a local variable and as a field in the generated closure. And when copying, you want to modify the same variable from multiple references, so aliasing semantics is the only reasonable thing to do...

like image 127
Tomas Petricek Avatar answered Dec 06 '22 03:12

Tomas Petricek


Ref is a type (int ref = ref<int>). Mutable is not a type, it's a keyword that allows you to update a value.

Example:

let (bla:ref<int>) = ref 0 //yup
let (bla:mutable<int>) = 3 //no!
like image 29
cfern Avatar answered Dec 06 '22 01:12

cfern