Thomas
Thomas

Reputation: 12107

Clarifying field types in F#

After some practice with F#, I have still some points where I need to clear confusion:

The question is specifically about fields in a type.

This is what I understand and, some must be wrong because the naming wouldn't make sense if I was right:

let x -> private read-only field, evaluated once
let mutable x -> private mutable field

val x -> public read-only field.. difference with let?
val mutable x -> public mutable field

member this.x -> private read-only field, evaluated every time
member val -> public mutable field.. difference with val? why no mutable keyword?

Can someone tell me what is right / wrong, or some concepts I may have gotten wrong.

Upvotes: 0

Views: 51

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243041

First of all, you can pretty much ignore val and val mutable. Those two are used with an older syntax for defining classes that is not exactly formally deprecated, but I would almost never use it when writing new normal F# code (there are some rare use cases, but I don't think it's worth worrying about those).

This leaves let and let mutable vs. member and member val.

  • let defines a private field that can only be accessed within the class. The value you assign to it is evaluated once. You can also define functions like let foo x = x + 1 or let bar () = printfn "hi" which have body that's evaluated when the function is called.

  • let mutable defines a private mutable field. This is initialized by evaluating the right-hand side, but you can later mutate it using fld <- <new value>.

  • member this.Foo = (...) defines a get-only property. The expression (...) is evaluated repeatedly whenever the property is accessed. This is a side-effect of how .NET properties work - they have a hidden get() method that's called whenever they are accessed, so the body is the body of this method.

  • member val Foo = (...) is a way of writing a property that is evaluated only once. In earlier versions of F#, this was not available, so you had to implement this functionality quite tediously yourself by definining a local field (to run the code once) and then returning that from a regular property:

    let foo = (...)
    member x.Foo = foo
    

Upvotes: 2

Related Questions