在F#中输入扩展名和成员可见性

时间:2013-04-05 08:47:09

标签: f# lexical-scope type-extension

F#具有名为"Type extension"的功能,使开发人员能够扩展现有类型。 有两种类型的扩展:内在扩展可选扩展。第一个类似于C#中的部分类型,第二个类似于方法扩展(但更强大)。

要使用内部扩展,我们应该将两个声明放入同一个文件中。在这种情况下,编译器会将两个定义合并为一个最终类型(即这是一种类型的两个“部分”)。

问题是这两种类型对不同的成员和值有不同的访问规则:

// SampleType.fs
// "Main" declaration
type SampleType(a: int) =
    let f1 = 42
    let func() = 42

    [<DefaultValue>]
    val mutable f2: int
    member private x.f3 = 42
    static member private f4 = 42

    member private this.someMethod() =
        // "Main" declaration has access to all values (a, f1 and func())
        // as well as to all members (f2, f3, f4)
        printf "a: %d, f1: %d, f2: %d, f3: %d, f4: %d, func(): %d"
            a f1 this.f2 this.f3 SampleType.f4 (func())

// "Partial" declaration
type SampleType with

    member private this.anotherMethod() =
        // But "partial" declaration has no access to values (a, f1 and func())
        // and following two lines won't compile
        //printf "a: %d" a
        //printf "f1: %d" f1
        //printf "func(): %d" (func())

        // But has access to private members (f2, f3 and f4)
        printf "f2: %d, f3: %d, f4: %d"
            this.f2 this.f3 SampleType.f4

我阅读了F#规范但没有找到任何想法为什么F#编译器区分值和成员声明。

在V.1规范的8.6.1.3 section中,“实例定义定义的函数和值是词法范围(因此隐式私有)到被定义的对象。”部分声明可以访问所有私有成员(静态和实例)。我的猜测是,通过“词法范围”规范作者特别指的是“主要”声明,但这种行为对我来说似乎很奇怪。

问题是:这种行为是故意的,背后有什么理由?

2 个答案:

答案 0 :(得分:10)

这是一个很好的问题!正如您所指出的那样,规范说“本地值词法范围到正在定义的对象”,但是看看F#规范,它实际上并没有定义词法范围在这种情况下的含义。

如您的示例所示,当前行为是对象定义的词法范围只是主要类型定义(不包括内部扩展)。我对此并不感到惊讶,但我发现其他解释也是有道理的......

我认为这样做的一个很好的理由是两种扩展应该表现得相同(尽可能多),并且您应该能够重构代码,使用其中一种来根据需要使用另一种扩展。这两种只是在封面下编译它们的方式不同。如果一种允许访问词法范围而另一种不允许访问词法范围,则该属性将被破坏(因为扩展成员在技术上不能这样做)。

那就是说,我认为这可以(至少)在规范中澄清。报告此问题的最佳方式是通过fsbugsmicrosoftcom发送电子邮件。

答案 1 :(得分:3)

我已将此问题发送至fsbugs microsoftcom,并得到Don Syme的回复:

  

嗨谢尔盖,

     

是的,这种行为是故意的。在类范围中使用“let”时,标识符在类型定义上具有词法范围。该值甚至可能不会放在字段中 - 例如,如果某个值未被任何方法捕获,则它将成为构造函数的本地值。这种分析是在课堂上进行的。

     

据我所知,您希望该功能像C#中的部分类一样工作。然而,它只是不起作用。

我认为术语“词汇范围”应该在规范中更清晰地定义,因为否则当前的行为对其他开发者来说也会令人惊讶。

非常感谢Don的回应!