开发者

'mutable' in type definition

开发者 https://www.devze.com 2022-12-19 06:24 出处:网络
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

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


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...


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!
0

精彩评论

暂无评论...
验证码 换一张
取 消