Reputation: 4062
let f x = System.Object.ReferenceEquals(x,x)
f id // false
I thought that at first it might because a function could be converted to a closure multiple times, but the above disproves that. Why does that last line return false
?
Upvotes: 1
Views: 49
Reputation: 12667
You likely have optimizations turned on. This time it's the opposite problem.
What happens if inlining is turned on?
id
will be rewritten to an instance of idFuncClass <: FSharpFunc
.
The whole expression will be rewritten to:
Object.ReferenceEquals(new fsharpfun1(), new fsharpfun1())
You can turning off inlining with:
[<MethodImpl(MethodImplOptions.NoInlining)>]
let f x = System.Object.ReferenceEquals(x,x)
You'll find that the comparison works again. But the bigger take-away is this - comparing two functions in F# is undefined behavior. In fact a function type doesn't even implement equality.
let illegal = id = id //this won't compile
Here's the relevant section in the F# Spec:
6.9.24 Values with Underspecified Object Identity and Type Identity
The CLI and F# support operations that detect object identity — that is, whether two object references refer to the same “physical” object.
For example,
System.Object.ReferenceEquals(obj1, obj2)
returns true if the two object references refer to the same object. Similarly,GetHashCode()
returns a hash code that is partly based on physical object identity ...The results of these operations are underspecified when used with values of the following F# types:
- Function types
- Tuple types
- Immutable record types
- Union types
- Boxed immutable value types
For two values of such types, the results of
System.Object.ReferenceEquals
andSystem.Runtime.CompilerServices.RuntimeHelpers.GetHashCode
are underspecified; however, the operations terminate and do not raise exceptions.An implementation of F# is not required to define the results of these operations for values of these types.
What the spec advises is to treat the actual function-type and its CLR implementations as a black-box.
Upvotes: 2