8

This is not about windows forms at all it's here only for the "background".

I was toying around Windows Forms when I got an error on an AddRange for a MenuStrip.Items requiring to cast ToolStripMenuItem into ToolStripItem

But I already have an AddRange for a Form.Controls before which didn't require casts.

After a little experimentation I managed to find that the error occurs when there are multiple overload for that AddRange so I tried to validate my thought :

type Foo () = class end
type Bar () = inherit Foo ()

type FooCollection () = class end // not really necessary

type Test1 () =
  member __.AddRange (col: FooCollection) = () // could be an int or anything instead
  member __.AddRange (foos: Foo []) = ()

type Test2 () = member __.AddRange (foos: Foo []) = ()

let lst1, lst2 = Test1 (), Test2 ()
lst1.AddRange [|Bar ()|] // error: have to explicitely cast => [|Bar () :> Foo|]
lst2.AddRange [|Bar ()|] // works

The question is simply why ; from my point of view the call is not ambiguous

Sehnsucht
  • 5,019
  • 17
  • 27
  • For me the question is why it works in test2, if you make the method static it stops working. – Gus Jul 07 '16 at 12:58
  • Test2 works for me with static method (Test1 still don't work obviously) – Sehnsucht Jul 07 '16 at 13:11
  • Can't edit the previous here is a sample from [ideone](http://ideone.com/KLGwRb) for the static test – Sehnsucht Jul 07 '16 at 13:17
  • Yes, I was testing with the wrong fsi session :) It also works with let bindings, so it's somehow bypassing F# type rules, since if you do ``[|Bar ()|] :> Foo[]`` it doesn't work. – Gus Jul 07 '16 at 13:19
  • _let binding_ ? you mean `let foos : Foo [] = [| Bar () |]` ? it's a wild guess but that works because it's another use of flexibility we give the type and there is an upcast between the two ; in `[| Bar ()|] :> Foo []` it's the whole array we try to upcast – Sehnsucht Jul 07 '16 at 13:29
  • @Gustavo - it's not bypassing F# type rules; consider `([| "test" |] : obj[])` vs. `([| "test" |] :> obj[])`. See http://stackoverflow.com/a/18303225/82959. – kvb Jul 07 '16 at 15:52
  • The way that arguments are elaborated differs between overloaded and non-overloaded methods. It's unclear to me to what extent this is intentional and specced, but see e.g. my edit in [this answer](http://stackoverflow.com/a/22612250/82959) for another place where it can occur. – kvb Jul 07 '16 at 15:59

1 Answers1

2

After reading the 14.4.3 F# spec (hinted by Gustavo, kudos to him)

The F# compiler determines whether to insert flexibility after explicit instantiation, but before any arguments are checked.

I understand that flexibility is never inserted for a method which have overloads because it would need argument checking to choose.

Community
  • 1
  • 1
Sehnsucht
  • 5,019
  • 17
  • 27
  • I don't think flexibility is involved; the question isn't whether you can pass a `Bar[]` to a function expecting a `Foo[]` (you can't - try it with a non-literal), it's whether to treat the literal itself as an instance of `Bar[]` or `Foo[]`. – kvb Jul 07 '16 at 15:56
  • From my (limited) understanding : When you have a non-literal the type is already "frozen" so it's the right one or not. end of story. When you have a non literal the type isn't "frozen" (to not say flexible) it depend on context. For a single method the context is clear so "an attempt is made to conform the parameter type to the argument type" (my way of describing it). For an overloaded method the context isn't that clear so the compiler doesn't bother trying attempt it has to be the developper to make it's intent clearer. – Sehnsucht Jul 07 '16 at 16:47
  • Yes, I think that's basically right - but that's not what the insertion of flexibility mentioned in 14.4.3 is about. Instead, that is strictly about accepting arguments of types which are statically known to be of subtypes of the method's argument types, which doesn't apply in this case. – kvb Jul 07 '16 at 17:09
  • I hope someone will come to enlighten us ; meanwhile I keep the answer to keep those comments. – Sehnsucht Jul 07 '16 at 17:53