Anthony Nichols
Anthony Nichols

Reputation: 1658

F# partially implemented interface in abstract class

I am trying to write an abstract class that partially implements an interface. I also want to set defaults for the non-implemented values. It seems that F# may not support that, but it is equally possible that I just can't get the syntax correct. Any help would be appreciated. This is where I am at so far:

type IDrawable =
    abstract member Position : Vector2
    abstract member ShortSymbol : int
    abstract member ForeColor : string
    abstract member BackColor : string
    abstract member Symbol : char
    abstract member Description : string

[<AbstractClass>]
type DrawableBase(position, shortSymbol, foreColor, backColor) =

    let position : Vector2 = position
    let shortSymbol : int = shortSymbol
    let foreColor : string = foreColor
    let backColor : string = backColor

    interface IDrawable with
        member this.Position = position
        member this.ShortSymbol = shortSymbol
        member this.ForeColor = foreColor
        member this.BackColor = backColor

        default this.Symbol = char this.ShortSymbol
        default this.Description = ""

    new(oldBase: DrawableBase, newPosition) = DrawableBase(newPosition, oldBase.ShortSymbol, oldBase.ForeColor, oldBase.BackColor)  

This is for a learning project so most of it doesn't really matter - I'm probably do a few other things wrong here as well - feel free to critique.

Upvotes: 3

Views: 613

Answers (2)

V.B.
V.B.

Reputation: 6382

I haven't heard about partial interface implementation, even though I have done some OOP work in F# with type inheritance and interfaces. You could achieve the same result with virtual member at the base class:

type IDrawable =
    abstract member Position : Vector2
    abstract member ShortSymbol : int
    abstract member ForeColor : string
    abstract member BackColor : string
    abstract member Symbol : char
    abstract member Description : string

[<AbstractClass>]
type DrawableBase(position, shortSymbol, foreColor, backColor) =

    let position : Vector2 = position
    let shortSymbol : int = shortSymbol
    let foreColor : string = foreColor
    let backColor : string = backColor

    abstract member Symbol : char
    default this.Symbol = char shortSymbol
    abstract member Description : string
    default this.Description = ""

    interface IDrawable with
        member this.Position = position
        member this.ShortSymbol = shortSymbol
        member this.ForeColor = foreColor
        member this.BackColor = backColor

        member this.Symbol = this.Symbol
        member this.Description = this.Description

Because interfaces in F# are explicit, I prefer to implement all interface members as a call to the corresponding type members. E.g. in the previous example the constructor complains that oldBase doesn't have members other than the two virtual ones that I have added:

new(oldBase: DrawableBase, newPosition) = DrawableBase(newPosition, oldBase.ShortSymbol, oldBase.ForeColor, oldBase.BackColor) 

One solution is to change the type of oldBase to IDrawable:

new(oldBase: IDrawable, newPosition) = DrawableBase(newPosition, oldBase.ShortSymbol, oldBase.ForeColor, oldBase.BackColor) 

Another solution is to add all methods to the type itself. That is more convenient because it allows to avoid explicit casting in many places and work with classes in C# way (where interfaces are implemented implicitly) without annoying :> in every place where one needs to call interface members:

[<AbstractClass>]
type DrawableBase(position, shortSymbol, foreColor, backColor) =

    let position : Vector2 = position
    let shortSymbol : int = shortSymbol
    let foreColor : string = foreColor
    let backColor : string = backColor

    member this.Position = position
    member this.ShortSymbol = shortSymbol
    member this.ForeColor = foreColor
    member this.BackColor = backColor

    abstract member Symbol : char
    default this.Symbol = char shortSymbol
    abstract member Description : string
    default this.Description = ""

    interface IDrawable with
        member this.Position = this.Position
        member this.ShortSymbol = this.ShortSymbol
        member this.ForeColor = this.ForeColor
        member this.BackColor = this.BackColor

        member this.Symbol = this.Symbol
        member this.Description = this.Description

    new(oldBase: DrawableBase, newPosition) = DrawableBase(newPosition, oldBase.ShortSymbol, oldBase.ForeColor, oldBase.BackColor) 

Note that in some rare cases you would want to implement interface not as a call to a type member, but directly as a call to a field or a private method (i.e. duplicate some code and have it as member this.Position = position inside interface as in the type member). This is because for type hierarchies, virtual methods and interfaces inlining at JIT level doesn't always work as with simple classes, so calling member this.Position = this.Position incurs an additional virtual call overhead. But this only matters when you need to nanooptimize, e.g. increase performance from 100 Mops to 150 Mops of a simple method.

Upvotes: 1

John Palmer
John Palmer

Reputation: 25516

Looking at the page for F# interfaces on MSDN here https://msdn.microsoft.com/en-us/library/dd233207.aspx

default is never valid for an interface implementation in a class.

However, again from the docs

However, you can provide a default implementation by also including a separate definition of the member as a method together with the default keyword

Upvotes: 0

Related Questions