7 people like it.

Private Implementation Inheritance without boilerplate

How to avoid delegation boilerplate in inhertance heavy OOP code while maintaining proper accessibility like seen here https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/seq.fs#L82 and mentioned in Expert F# 2.0 "Using Partially Implemented Types via Implementation Inheritance " Uses auto-properties that only work with F# 3.0

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
71: 
72: 
73: 
74: 
75: 
76: 
77: 
78: 
79: 
80: 
81: 
82: 
(*
How to avoid delegation boilerplate in inheritance heavy OOP code while maintaining proper accessibility
like seen here https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/seq.fs#L82
and mentioned in Expert F# 2.0 "Using Partially Implemented Types via Implementation Inheritance "

Quote from the book:
"If implementation inheritance is used, you should in many cases consider making all implementing 
classes private or hiding all implementing classes behind a signature. For example, the 
Microsoft.FSharp.Collections.Seq module provides many implementations of the seq<'T> interface 
but exposes no implementation inheritance."

Some explanation on why implementation inheritance should be avoided.
http://sharp-gamedev.blogspot.com/2011/07/why-inheritance-for-code-reuse-should.html

This snippet should remedy the boilerplate mentioned in the following link therefore making it worthwhile.
http://sharp-gamedev.blogspot.com/2011/08/is-it-worth-it.html 

In this example only the explicit interface implementation of the base class will have the delegation boilerplate.
We inherit from the base class with an object expression and override some members and then immediately upcast to 
the interface.
This way we also simulate a protected Prop setter since the interface only exposes the getter

It also demonstates the use of F# 3.0 autoproperties.
*)

type IGameScreen =
    abstract Prop : string
    abstract Update : unit -> string

[<AbstractClass>]
type GameScreenBase() =
    member val Prop = "GameScreen.Prop" with get, set
    abstract Update : unit -> string
    interface IGameScreen with
        member o.Prop = o.Prop
        member o.Update() = o.Update()

let loadingScreen () =
    { new GameScreenBase(Prop = "loadingScreen.Prop") with
        override o.Update() = "loadingScreen.Update"  } :> IGameScreen
        
type IMenuScreen =
    inherit IGameScreen
    abstract MenuMethod : unit -> string

[<AbstractClass>]
type MenuScreenBase() =
    inherit GameScreenBase(Prop = "MenuScreen.Prop")
    abstract MenuMethod : unit -> string
    default o.MenuMethod() = 
        o.Prop <- "MenuScreenBase.Prop"
        "MenuScreen.MenuMethod"
    interface IMenuScreen with
        member o.MenuMethod() = o.MenuMethod()

let pauseMenuScreen () =
    { new MenuScreenBase(Prop = "pauseMenuScreen.Prop") with
        //override o.MenuMethod() = 
        //    o.Prop <- "pauseMenuScreen.Prop"
        //    "pauseMenuScreen.MenuMethod"
        override o.Update() = "pauseMenuScreen.Update" } :> IMenuScreen

module Example =
    let gameScreens : IGameScreen[] = [| loadingScreen () ; pauseMenuScreen () |]

    let testGameScreens (screens : IGameScreen[]) =
        for gs in screens do
            gs.Prop |> printfn "%s"       
            gs.Update() |> printfn "%s"

    testGameScreens gameScreens

    let menuScreens : IMenuScreen[] = [| pauseMenuScreen () |]

    let testMenuScreens (screens : IMenuScreen[]) =
        for ms in screens do
            ms.Prop |> printfn "%s"       
            ms.Update() |> printfn "%s"
            ms.MenuMethod() |> printfn "%s"
            ms.Prop |> printfn "%s"

    testMenuScreens menuScreens
abstract member IGameScreen.Prop : string

Full name: Script.IGameScreen.Prop
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
abstract member IGameScreen.Update : unit -> string

Full name: Script.IGameScreen.Update
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
Multiple items
type AbstractClassAttribute =
  inherit Attribute
  new : unit -> AbstractClassAttribute

Full name: Microsoft.FSharp.Core.AbstractClassAttribute

--------------------
new : unit -> AbstractClassAttribute
Multiple items
type GameScreenBase =
  interface IGameScreen
  new : unit -> GameScreenBase
  abstract member Update : unit -> string
  member Prop : string
  member Prop : string with set

Full name: Script.GameScreenBase

--------------------
new : unit -> GameScreenBase
val set : elements:seq<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.set
abstract member GameScreenBase.Update : unit -> string

Full name: Script.GameScreenBase.Update
type IGameScreen =
  interface
    abstract member Update : unit -> string
    abstract member Prop : string
  end

Full name: Script.IGameScreen
val o : GameScreenBase
override GameScreenBase.Prop : string

Full name: Script.GameScreenBase.Prop
property GameScreenBase.Prop: string
override GameScreenBase.Update : unit -> string

Full name: Script.GameScreenBase.Update
abstract member GameScreenBase.Update : unit -> string
val loadingScreen : unit -> IGameScreen

Full name: Script.loadingScreen
type IMenuScreen =
  interface
    inherit IGameScreen
    abstract member MenuMethod : unit -> string
  end

Full name: Script.IMenuScreen
abstract member IMenuScreen.MenuMethod : unit -> string

Full name: Script.IMenuScreen.MenuMethod
Multiple items
type MenuScreenBase =
  inherit GameScreenBase
  interface IMenuScreen
  new : unit -> MenuScreenBase
  abstract member MenuMethod : unit -> string
  override MenuMethod : unit -> string

Full name: Script.MenuScreenBase

--------------------
new : unit -> MenuScreenBase
abstract member MenuScreenBase.MenuMethod : unit -> string

Full name: Script.MenuScreenBase.MenuMethod
val o : MenuScreenBase
override MenuScreenBase.MenuMethod : unit -> string

Full name: Script.MenuScreenBase.MenuMethod
override MenuScreenBase.MenuMethod : unit -> string
val pauseMenuScreen : unit -> IMenuScreen

Full name: Script.pauseMenuScreen
module Example

from Script
val gameScreens : IGameScreen []

Full name: Script.Example.gameScreens
val testGameScreens : screens:IGameScreen [] -> unit

Full name: Script.Example.testGameScreens
val screens : IGameScreen []
val gs : IGameScreen
property IGameScreen.Prop: string
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
abstract member IGameScreen.Update : unit -> string
val menuScreens : IMenuScreen []

Full name: Script.Example.menuScreens
val testMenuScreens : screens:IMenuScreen [] -> unit

Full name: Script.Example.testMenuScreens
val screens : IMenuScreen []
val ms : IMenuScreen
abstract member IMenuScreen.MenuMethod : unit -> string

More information

Link:http://fssnip.net/aS
Posted:7 years ago
Author:Associat0r
Tags: xna , oop , inheritance , object-oriented programming , object expressions , classes , interface