43

Is there a better way of modeling data in F# to avoid needing it?

Daniel
  • 47,404
  • 11
  • 101
  • 179

2 Answers2

42

The protected modifier can be quite problematic in F#, because you often need to call members from a lambda expression. However, when you do that, you no longer access the method from within the class. This also causes confusion when using protected members declared in C# (see for example this SO question). If you could declare a protected member, the following code could be surprising:

type Base() = 
  protected member x.Test(a) = a > 10

type Inherited() = 
  inherit Base()
  member x.Filter(list) =
    list |> List.filter (fun a -> x.Test(a))

This code wouldn't work, because you're calling Test from a lambda function (which is a different object than the current instance of Test), so the code wouldn't work. I think this is tha main reason for not supporting the protected modifier in F#.

In F# you typically use implementation inheritance (that is, inheriting from a base class) much less frequently than in C#, so you shouldn't need protected as often. Instead, it is usually preferred to use interfaces (in the object-oriented F# code) and higher-order functions (in the functional code). However, it is difficult to say how to avoid the need for protected in general (other than by avoiding implementation inheritance). Do you have some specific example which motivated your question?

Community
  • 1
  • 1
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • 35
    This is true, but it's an implementation artifact of the compiler. There's no fundamental reason that an F#-like .NET language couldn't generate a nested class to house the closure and have the intended semantics. – kvb Mar 05 '10 at 23:27
  • Good explanation. It's easy to forget about objects the F# compiler creates to support lambdas and other functional constructs. I'm writing an ORM that will be used frequently from C#. It uses something of a provider model. There's an abstract Repository class, which might be extended by SqlRepository, OracleRepository, etc. I wanted a protected method that loads schema information for a table. Any ideas of a better way to do this? – Daniel Mar 05 '10 at 23:27
  • @kvb - I thought the same thing. Is there a way the compiler could check if a protected member is being accessed from a lambda in a derived class? – Daniel Mar 05 '10 at 23:29
  • 2
    See this blog post by Eric Lippert (http://blogs.msdn.com/ericlippert/archive/2005/11/14/why-are-base-class-calls-from-anonymous-delegates-nonverifiable.aspx) for a discussion of how a similar problem caused the C# compiler to emit unverifiable code previously, although the code-gen approach has been changed to fix this in C# 4. – kvb Mar 05 '10 at 23:31
  • 1
    It may be just an implementation artifact of the compiler, but it's a question whether allowing this would be an expected behavior. For example you could easily write a member that returns lambda function, which calls the `protected` member. I belive this is against the principle of `protected` members. In general, I think that the notion of protected members just doesn't work very well with functional features and since F# is still mostly a functional language, this is a logical trade-off. – Tomas Petricek Mar 06 '10 at 00:04
  • 11
    @Tomas - I agree with the second half of your comment: I can't remember ever missing `protected` members when using F#. As to the first half of your comment, though, I don't see this as any different than exposing a public member which wraps a protected member. C#'s approach seems very intuitive to me, and I haven't seen any complaints/confusion around it. – kvb Mar 06 '10 at 01:26
  • 3
    This is one of those places where F# guys don't feel any compassion for C# folks. Of course it can be implemented, but as in c#, the F# language reached a certain stage where the authors (main contributors) don't want to add anything even if it is obviously missing. Another example: type inference in F# is cool, but incomplete, you can achieve clever hacks though, but you cannot do it simple and explicitly: overloading module operators or module functions, using unicode chars for custom operators. – Liviu Mar 07 '14 at 12:43
  • 5
    Exactly @Liviu when I asked about this on twitter I received the answer that "although F# support object orientation it does so in an opinionated way". I think that's a lot closer to the real reason F# doesn't support defining protected members: Someone who doesn't write a lot of object oriented code doesn't think it's important. Unfortunately without support for protected F# cannot be considered a first-class citizen in .NET. – U62 Feb 20 '15 at 16:23
8

As to whether F# enables a better way of modeling data, signature files allow finer grained visibility decisions than internal does in C#, which is often very nice. See Brian's comment here for a little bit more explanation. This is independent of support (or lack thereof) for protected, though.

kvb
  • 54,864
  • 2
  • 91
  • 133