开发者

F# handling values and references

开发者 https://www.devze.com 2023-02-10 10:22 出处:网络
I need to understand something very important regarding F#: how it handles references and values. I know that F# defines immutable and mutable objects and also know the reason why.

I need to understand something very important regarding F#: how it handles references and values. I know that F# defines immutable and mutable objects and also know the reason why.

But there is one thing that I do not know: how are objects treated?

开发者_Python百科I mean, in C# everything is a pointer and when assigning to an object the reference of another one, data are the same, and we'll have two pointers pointing the same data.

So in C# if I have this:

Object myobj1 = new Object();
Object myobj2 = myobj1;
bool myobj1 == myobj2; // It is true

Well, what about f#?

let myvar: MyObj = new MyObj ()
let myvar2: MyObj = myvar

What's the situation here? Does the assignment involves copy? or not.

And, generally speaking, what's f# approach to this topic? (I mean value vs reference).


When working with reference types and value types, F# behaves just like C#.

  • When you have a reference type, it works with a reference to an instance in the heap.
  • When you have a value type (built-in, declared in C# or declared in F# using Struct attribute),
    the value is copied when you assign it to another value or pass as argument.

The only notable difference is that standard F# types (discriminated unions, records, lists, arrays and tuples) have structural equality semantics. This means that they are compared by comparing the actual value stored in them and not by comparing references (even if they are reference types). For example, if you create two lists of tuples containing the same data you get:

> let l1 = [ ("Hello", 0); ("Hi", 1) ]
  let l2 = [ ("Hi", 1); ("Hello", 0) ] |> List.rev;;
(...)

> l1 = l2;;
val it : bool = true

You get true even though lists and tuples are reference types. If you compare the references however (EDIT: Added sample inspired by kvb):

> System.Object.ReferenceEquals(l1, l2);;
val it : bool = false

The use of structural equality makes sense in F# because the types are immutable - when you create two values containing the same data, they will always be the same. If they were mutable, you could change one and they wouldn't be equal anymore - that's why it makes more sense to use reference equality for mutable types.


As you can convince yourself with the following simple experiment, F#'s behavior is the same as C#'s:

printfn "%b" (myvar = myvar2)  // true

Or better yet:

printfn "%b" (obj.ReferenceEquals(myvar, myvar2)) // true

since as Tomas points out, the behavior of (=) can be a bit subtle.

From my perspective, there isn't really any logical alternative; what else could myvar2 possibly contain? There isn't any general mechanism for duplicating objects of arbitrary types, so the only behavior that makes sense is for myvar and myvar2 to contain equal references.

0

精彩评论

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