Thomas
Thomas

Reputation: 12107

let vs member for private functions, in F#

Let's consider this code:

type TransactionTypes =
| TransactionType1
| TransactionType2

type Test() =

    let mutable lastTransactionType1 = DateTime.MinValue
    let mutable lastTransactionType2 = DateTime.MinValue

    let getLastTransaction transaction =
        match transaction with
        | TransactionType1 -> lastTransactionType1
        | TransactionType2 -> lastTransactionType2

    let updateLastTransaction transaction =
        match transaction with
        | TransactionType1 -> lastTransactionType1 <- DateTime.UtcNow
        | TransactionType2 -> lastTransactionType2 <- DateTime.UtcNow

Now (with the understanding that I'm still learning F#), I would like to clarify a couple things:

Something like:

let a = DateTime.Now

does a permanent binding, so 'a' will always be the same time on subsequent uses.

But, my understanding is that if there is a parameter, like:

let a anyParameter = DateTime.Now

will be re-evaluated every time due to the presence of the parameter. Is that correct?

In the code above, the two let statements (getLastTransaction and updateLastTransaction) are private to the type (Test)

I could also have implemented them as:

member private this.getLastTransaction = ...
member private this.updateLastTransaction = ...

Is there any reason, for private functions to prefer let vs. member private this? "let mutable" already implies the this. so the fields are accessible by both forms.

So, what is the advantage of one form vs. the other?

Upvotes: 0

Views: 365

Answers (2)

Asti
Asti

Reputation: 12677

In addition to Tomas' answer:

  let mutable lastTransactionType1 = DateTime.MinValue

is equivalent in C# to:

internal DateTime lastTransactionType1 = DateTime.MinValue;

and

member private this.getLastTransaction ...

is the same IL as far as IL is concerned with

let getLastTransaction ...

In equivalent C#, both are

internal DateTime getLastTransactionMember(TransactionTypes transaction)
{
    if (transaction.Tag != 1)
    {
        return lastTransactionType1;
    }
    return lastTransactionType2;
}

But for using F# in an idiomatic way, you would want to go with let. There's also a difference in that member does let you use the methods in bindings before their declaration, which might be useful in some cases (read: hacks)

let getType1 = this.getLastTransactionMember TransactionType1 //this compiles

member private this.getLastTransactionMember transaction =
        match transaction with
        | TransactionType1 -> lastTransactionType1
        | TransactionType2 -> lastTransactionType2

Upvotes: 2

Tomas Petricek
Tomas Petricek

Reputation: 243061

When you are working with members, F# inherits a lot of things from the .NET object model. A .NET object can have a couple of different things:

  • Fields - those are storing a value (just like fields of a record). They can be mutable or immutable.
  • Methods - those can be invoked with zero or more arguments (like functions)
  • Properties - those have no arguments (like fields); they can be read or written, but when this happens, some code is invoked. A property is basically a pair of getter and setter methods.

In F#, some of this is less visible. However, let corresponds to a field and member with arguments corresponds to a method. Your tricky case is a member without arguments. For example:

type A() = 
  member x.Foo = printfn "Hi"; 42

Will Hi be printed only once, or will it be printed each time you access Foo? To answer, it's useful to know that Foo is a property with a getter. The above is actually a syntactic sugar for the full version:

type A() = 
  member x.Foo 
    with get() = printfn "Hi"; 42

Now you can see that there is a method behind the Foo property! Each time you access Foo, the compiler will generate a call to the get() method, so Hi will be printed repeatedly.

Upvotes: 3

Related Questions