Looks like a bug, eh?

Even wierder, it works with records:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 

type foo2 = { Z: int } with
  member x.ZZ = x.Z

type bar(o:Other) =
  member x.NowItWorks = o.Foo.Z // remove this line and it breaks
  member x.AAA = o.Foo.ZZ

and Other() =
  let f = {Z = 3 } 
  member x.Foo = f 
  member x.Bla = new bar(x)

BUT, only if you access the field -- if you just access the member, it breaks.

By on 4/3/2009 11:46 AM ()

Weird stuff. Some stuff I didn't previously know the details of...

This is all by design. The type-inference algorithm is described in some gory detail in the spec, but the rough idea is that it's top-to-bottom, outside-in, left-to-right inference. "o" is of type Other, but what is the type of "o.Foo"? It's obvious if you look at the <i>body <i>of "Other.Foo" and see "foo", but F# hasn't got to that point yet, it's still just starting to go inside bodies in top-to-bottom fashion. As a result, you can make the error go away like suggested here: <code lang=fsharp> type foo () = member x.Z = 100 type bar(o:Other) = member x.AAA = o.Foo.Z // Error here, unless and Other() = let f = new foo() member x.Foo(*:foo*) = f // you uncomment this </code> (e.g. by adding an annotation on the 'outside' of the 'Foo' property, so its type is known before looking into its body). Alternatively, of course, you can reorder the types in this example (type Other...and bar...). It is a little strange that the order of 'type...and...' can 'matter', but those are the consequences of the language type inference rules. Records have different semantics, largely due to OCaml-compatibility; a uniquely-named record field automagically implies a type of the expression it's a part of, for example <code lang=fsharp> type MyRecord = { Yadda : string } let f x = x.Yadda </code> infers the type of 'f' (that 'x' is a 'MyRecord'). But that rule is kinda ridiculous in an OO context: <code lang=fsharp> let g x = x.Name // is x a System.Type, or a System.ServiceModel.Description.ContractDescription, or ... </code> where lots and lots of classes exist and lots of property names overlap. So effectively 'records' (and their field names) are 'special' to be more like OCaml, but they are the exception rather than the rule. Most of the time, if you want to do x.Blah, you must already 'know' the type of 'x'.

By on 4/3/2009 5:00 PM ()

Thank you !

By on 4/4/2009 1:57 AM ()

Wow, thanks for the good explanation and details here. So the good news is that this only hurts with inferred member types. Vals, abstract, etc. will all be fine.

By on 4/3/2009 5:23 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper