繁体   English   中英

具有类型和接口继承的F#奇怪行为

[英]F# strange behavior with type and interface inheritance

这是一段代码,经过几次试验和错误后才能运行,但我不明白为什么它以这种特殊方式工作? 它是按设计制定的,规则是在一些规范中写成的,或者在这种情况下是偶然的吗? 代码中的注释解释了这一切,但具体问题是:

为什么类型B_from_A没有看到,对于插槽IA.Item已经由母公司实现的A ,但随后只允许部分实现的IA ,所以它实际上是看到SharedMethod在父已经实施。

open System
open System.Collections.Generic

type IA = // only read methods
    abstract Item : int -> int with get
    abstract SharedMethod : int -> int

type IB = // allows in-place changes
    inherit IA
    abstract Item : int -> int with get, set

type IC = // immutable, returns new version with changes
    inherit IA
    abstract Set: int -> int -> IC

type A() =
    let dic = Dictionary<int,int>() // some complex internal data structure
    member internal this.Dic = dic
    member this.SharedMethod(i) = pown dic.[i] 2
    interface IA with
        member this.Item with get(i) = dic.[i]
        member this.SharedMethod(i) = this.SharedMethod(i) // custom operation on item

type B_from_A() =
    inherit A()
    // without this partial implementation I get an error:
    // Script1.fsx(111,18): error FS0361: The override 'get_Item : int -> int' 
    // implements more than one abstract slot, e.g. 'abstract member IB.Item : int -> int with get' 
    // and 'abstract member IA.Item : int -> int with get'
    interface IA with // partial interface implementation
        member this.Item with get(i) = this.Dic.[i] // required to remove error FS0361
        // !!! but there is no this.SharedMethod(i) here, so the type knows that this slot is 
        // implemented by parent A. Why it asks me to explicitly add Item get here?

    interface IB with
        member this.Item 
            with get(i) = this.Dic.[i] // implements more than one abstract slot without IA above
            and set i v = this.Dic.[i] <- v



type B() = // independent implementation
    let dic = Dictionary<int,int>()
    interface IA with
        member this.Item with get(i) = dic.[i]
        member this.SharedMethod(i) = pown dic.[i] 2
    interface IB with
        member this.Item  
            with get(i) = dic.[i]  
            and set i v = dic.[i] <- v
// If go from B to A, type A_from_B() won't be able to hide mutation methods in IB?
// It is more natural to add functionality than to hide or block it like some SCG ReadOnly collections do (e.g. throw on Add with InvalidOp)
// Therefore keep data structure inside A but add methods to change it inside B_from_A

另外,我在哪里可以快速简短地阅读抽象槽和F#多态实现中的所有低级机制?

此行为完全由规范定义

首先来自8.14.3接口实现:

接口实现的每个成员都按如下方式检查:

·该成员必须是实例成员定义。

·应用调度槽推理(第14.7节)。

·在假设“this”变量具有封闭类型的情况下检查成员。

然后是引用的部分:

14.7调度插槽推断F#编译器在处理其成员之前将Dispatch Slot Inference应用于对象表达式和类型定义。 对于对象表达式和类型定义,以下是对Dispatch Slot Inference的输入:

·正在实施的类型ty0。

·一组成员覆盖xM(arg1 ... argN)。

·一组附加接口类型ty1 ... tyn。

·另一组成员覆盖每个tyi的xM(arg1 ... argN)。

Dispatch slot推断将每个成员与收集的类型定义或继承的唯一抽象成员或接口成员相关联。

因此,每个函数只能工作一次 - 您无法获得所需的双重实现。

您描述的行为发生是因为IB继承了IA ,它们都定义了Item属性访问器。 因此, B_From_A.IB.Item属性访问器实现有两个可用的插槽。 但是,当您添加B_From_A.IA.Item实现时,已经占用了一个插槽,因此类型推断没有任何歧义 - 只有IB.Item仍可供B_From_A.IB.Item实现。

编辑

为了理解底层机制,重要的是要知道在F#中实现接口层次结构有两种不同的方法:

// ----- A hierarchy of interfaces
type IFoo = abstract FooMember: int

type IBar =
    inherit IFoo
    abstract BarMember: int

// Approach 1: Implement IFoo "explicitly".
// In the object browser, you will see both IFoo and IBar as parents of FooBar.
type FooBar =
    interface IFoo with member this.FooMember = 0
    interface IBar with member this.BarMember = 0

// Approach 2: Implement IFoo "implicitly" (as part of IBar).
// In the object browser, you will only see IBar as parent of FooBar.
type FooBar =
    interface IBar with
        member this.FooMember = 0
        member this.BarMember = 0

现在,如果IFooIBar都有一个具有完全相同签名的成员(例如,在您的示例中,是一个Item属性访问器),并且您只通过FooBar.IBar.Item实现了该成员,那么类型推断歧义将会必然会出现,因为它是未定义的行为, FooBar.IBar.Item是否应该实现IBar.ItemIFoo.Item

因此,您的问题的答案是:

  • “......为什么它以这种特殊方式起作用”:见上文
  • “它是否符合设计”:是的,也看到@ John的回答。
  • “为什么类型B_from_A没有看到,对于插槽IA.Item已经由母公司执行A ”:你的前提是不正确。 编译器确实看到了它,但它无法知道B_from_A.IB.Item是否应该
    • 重新实现 (在A中)已经实现的IA.Item ,或
    • 实现 IB.Item
  • “但是它只允许部分实现IA ,所以它实际上看到SharedMethod已经在父级中实现了。” 如上所述,它认为这两个IA.SharedMethodIA.Item已经由母公司实现的A ,但不确定性是不相关的“看或不看”,在任何预先存在的实现A

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM