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: 
(*
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 we 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 making it worthwhile.
http://sharp-gamedev.blogspot.com/2011/08/is-it-worth-it.html 

In this example only the base classes have the delegation boilerplate and 
we simulalte a protected Prop setter while keeping the implementations private.

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 OnCancel : unit -> string

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

let pauseMenuScreen () =
    { new MenuScreenBase(Prop = "PauseMenuScreen.Prop") with
        //override o.OnCancel() = "pauseMenuScreen.OnCancel"
        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.OnCancel() |> 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 OnCancel : unit -> string
  end

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

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

Full name: Script.MenuScreenBase

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

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

Full name: Script.MenuScreenBase.OnCancel
override MenuScreenBase.OnCancel : 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.OnCancel : unit -> string

More information

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