blob: a84f96efb047aab931c0fbe3aeeacabdf0719b43 (
plain)
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
|
open FunctionalObjects
// A record is like an interface
type Printer = {
PrintMessage : string -> unit
}
// Let's define a printHelloWorld function which uses the Printer interface.
//
// Notice that the type annotation is not required because Printer is a record
// and F# can infer the type of the variable based on the PrintMessage field.
//
// Because this pattern uses a concrete type for the interface, no runtime
// reflection is needed and type checking happens completely at compile time.
let printHelloWorld (printer : Printer) =
printer.PrintMessage "Hello World"
// An instance of the record is a class aka an implementation of the interface
let basePrinter : Printer =
{ PrintMessage = fun s -> printfn "Message: %s" s }
printfn "Using the base printer:"
printHelloWorld basePrinter
// We can create a sub-class of the base printer using Object.derive
//
// Object.derive is simply
// let derive f o = f o
// so it's completely syntactic sugar
let screamingPrinter : Printer =
basePrinter
|> Object.derive (fun b ->
{ b with
// We choose which methods to override
PrintMessage =
fun s -> b.PrintMessage (s.ToUpper()) })
// printHelloWorld doesn't have to change when we switch the Printer.
printfn "Using the screaming printer:"
printHelloWorld screamingPrinter
|