hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

Recursive types error

Last post 04-04-2009, 1:57 by Julien. 4 replies.
Sort Posts: Previous Next
  •  04-03-2009, 11:02 9753

    Recursive types error

    Hi

    why does the following raise an error ?



    type foo () =
      member x.Z = 100

    type bar(o:Other) =
      member x.AAA = o.Foo.Z //Error : lookup on object of indeterminate based on information prior to this point

    and Other() =
      let f = new foo()
      member x.Foo = f

    Since "o" is specified to be of type "Other", shouldn't o.Foo.Z be implicited ?

    Thanks


    http://lepensemoi.free.fr
  •  04-03-2009, 11:46 9754 in reply to 9753

    Re: Recursive types error

    Looks like a bug, eh?

    Even wierder, it works with records:



    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.

  •  04-03-2009, 17:00 9772 in reply to 9754

    Re: Recursive types error

    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 body 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:


    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

    (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


    type MyRecord = { Yadda : string }

    let f x = x.Yadda

    infers the type of 'f' (that 'x' is a 'MyRecord').  But that rule is kinda ridiculous in an OO context:


    let g x = x.Name // is x a System.Type, or a System.ServiceModel.Description.ContractDescription, or ...

    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'.

  •  04-03-2009, 17:23 9773 in reply to 9772

    Re: Recursive types error

    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.

  •  04-04-2009, 1:57 9775 in reply to 9772

    Re: Recursive types error

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems