Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding a change to protected/base member usage in F# 3.0

F# 3.0 adds stricter checks for calls to base and protected members. I have something like the following abstract class in C# that has protected static helper methods to be used by derived classes.

public abstract class Processor {
    public abstract void Process();
    protected static void Helper(object arg) { }
}

In F#, one of those helper methods is passed as a first-class function:

type DerivedProcessor() =
  inherit Processor()

  let init f =
    f ()

  override x.Process() =
    init Processor.Helper

It compiles without complaint in 2.0, but in 3.0 produces an error:

A protected member is called or 'base' is being used. This is only allowed in the direct implementation of members since they could escape their object scope.

OK, it's easy enough to comply, just wrap the call in another static member

static member private HelperWrapper(arg) = Processor.Helper(arg)

and pass that intead. But why?

C# has no problem with this same pattern.

public class HappyToCompile : Processor {
    private void Init(Action<object> f) {
        f(null);
    }

    public override void Process() {
        Init(Helper);
    }
}

The questions:

  1. Why were the stricter checks added?
  2. (and related) What terrible problem does such a trivial workaround address?
  3. Is there a better design that this is supposed to encourage?
like image 619
Daniel Avatar asked Aug 24 '12 15:08

Daniel


1 Answers

Using my psychic language design skills, I'd guess that F# 2.0 is generating unverifiable code. See this post on Eric Lippert's blog for an explanation of a related issue in C# (which has been fixed since C# 4, IIRC).

In short, when you create an F# function you are really creating a new class deriving from FSharpFunc<_,_>, and calling your protected method from within that class isn't valid since it's not in the inheritance chain.

Of course, rather than disallowing these calls, the compiler could just do what you're doing (create a private method and use that), but perhaps the benefits were thought not to outweigh the cost of implementing that improvement.

like image 164
kvb Avatar answered Oct 24 '22 23:10

kvb