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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With