Marko Grdinić
Marko Grdinić

Reputation: 4062

Why does reference equality for functions which are bound to the same variable return false?

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

Answers (1)

Asti
Asti

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

Related Questions