Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 654
Anthony Nichols Avatar asked Sep 03 '26 10:09

Anthony Nichols


1 Answers

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.

like image 106
V.B. Avatar answered Sep 07 '26 06:09

V.B.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!