Reputation: 1658
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
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
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