Franco Tiveron
Franco Tiveron

Reputation: 2896

F# strange difference in resolving class method calls

Given the following F# code

type MyClass = class end

type MyWorker1() = 
    (*1*)member this.DoWork(myObject: MyClass) = ()
    (*2*)member this.DoWork(myObjects: MyClass seq) = myObjects |> Seq.iter this.DoWork //Resolves to (*1*)

type MyWorker2() = 
    (*3*)member this.DoWork(myObject: #MyClass) = ()
    (*4*)member this.DoWork(myObjects: #MyClass seq) = myObjects |> Seq.iter this.DoWork //Resolves to (*4*)

in MyWorker2 the call this.DoWork is resolved as recursive call. I expected to behave as in MyWorker1, that is call (*3*).

Can someone explain the reason for this difference?

Upvotes: 3

Views: 92

Answers (1)

Abel
Abel

Reputation: 57149

As already reported by @Gus on Slack, this is likely a bug, good you reported it! Note that it appears to happen only with seq, not with other collection types like array or list. It also doesn't happen when you use let bindings instead of member or static member.

This is probably because let bindings cannot be self-referential unless you add rec. By adding rec, you actually do see the same behavior again, but this time it is expected.

I'm surprised that F# adds an extra constraint as 'a :> seq<'a>, I find this really odd.

Since this is SO, and I'm gonna assume this blocks a certain pattern of coding, here's a workaround. It's a little extra indirection, but if you need the above pattern in real world code, here's how you can do it:

type MyWorker2() = 
    let doWork1(myObject: #MyClass) = ()
    let doWork2(myObjects: seq<#MyClass>) = myObjects |> Seq.iter (fun x -> doWork1 x) //Resolves to (*4*)

    member this.DoWork(myObject: #MyClass) = doWork1 myObject
    member this.DoWork(myObjects: seq<#MyClass>) = doWork2 myObjects

One observation, if you make the private let-bindings the same name (i.e. just doWork instead of doWork1|2), the issue with the extra type restriction appears on the first DoWork. But this time it makes sense, as the let-bindings shadow one another.

Upvotes: 3

Related Questions