19

Is the reason F# doesn't support nested classes technical, stylistic, arbitrary?

Glancing over the BCL in Reflector, nested classes are used for enumerators, DynamicMetaObjects, and probably a few other things.

That piqued my curiosity about F# not having this feature. I'm aware that there are other ways to do the same thing. I'm mostly curious.

Daniel
  • 47,404
  • 11
  • 101
  • 179

2 Answers2

22

I suppose nested classes were not a core feature of the .NET object model and it was simply dropped to save the resources. There may be some technical difficulties (i.e. with visibility or with recursive type definitions), but I don't think that would be a major problem.

For many cases where one would use nested classes in C#, such as iterators, you can nicely use object expressions, so I guess they are in some ways replacement for nested classes:

type Collection() =
  member x.GetEnumerator() = 
    let n = ref 0
    { new IEnumerator with
        member x.Current = box n.Value
        member x.MoveNext() = incr n; true
        member x.Reset() = n := 0 }

Although this is quite similar to nested classes, it isn't compiled as nested class and the body of an object expression cannot access private members of Collection. I guess supporting this would complicate compilation of expressions a bit, because object expressions can appear outside of a class context...

Actually, it is possible to access private members from object expression, although the code still isn't compiled as a nested class. See comments for details.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • 1
    One small correction: it _is_ possible to reference `let` bindings/private members of the enclosing type from an object expression. This, in my view, makes them a better solution than nested classes. – Daniel Jan 20 '12 at 23:08
  • 1
    @Daniel You're right - you can access private members (I had a bug in my test). Interestingly, when you do that, the member you're accessing is either inlined or compiled as `internal` to make this access safe (but F# compiler treats it as `private`). – Tomas Petricek Jan 21 '12 at 13:41
  • 4
    @Tomas: Actually, according to the F# specification, "The CLI compiled form of _all_ non-public entities is internal." ... which is why one should not give non-F# clients the [] privilege... they will see everything that is _private_ in the F# assembly as _internal_! – Marc Sigrist Jan 24 '12 at 18:44
  • I wanted to cheat and created the module with the same name, but compiler create a static class with the name with `Module` at the end. I expected it will merge module and type in single class ='( – Pavel Voronin Dec 08 '20 at 20:08
3

F# is largely based on Caml, which does not have nested classes.

It probably wasn't added simply because it's not very high-priority. Since you can declare data types that are not visible outside of a module, allowing inner classes would not make all that much of a difference in how well-encapsulated your code can be.

Sean U
  • 6,730
  • 1
  • 24
  • 43
  • 11
    That's most likely not the case - although F# is largely based on OCaml, the object model used in F# is much more based on .NET than on OCaml. – Tomas Petricek Jan 20 '12 at 22:38
  • +1 for mentioning that they are unnecessary because you can use signature files to hide them. – YellPika Aug 17 '13 at 02:01