F# programs are built around types. With types, we group related pieces of data together. We add behavior (in functions and properties) to our types.
When specifying a type, we can add initialization logic. This ensures each instance of the type is valid. We can specify members of a type.
Here we introduce an Animal type. To create an animal we must specify an int
for its size (this is like its constructor).
int
. It returns the size times 10.type Animal(s : int) = // Store the argument in the object. let mutable size = s // Write a helpful message. do printfn "Animal created, size = %A" size // For Weight, return size times 10, an int. member x.Weight : int = size * 10 // Create an Animal with size 5. let animal = Animal 5 // Get the Weight of the animal. let weight = animal.Weight printfn "%A" weightAnimal created, size = 5 50
Properties help us control how a type is used. Here we introduce a type Box that has a Color property. With the get()
and set()
keywords we add accessors.
get()
accessor. This returns the value of the "color" mutable field.type Box() = // A mutable color field. let mutable color : string = null // A Box has a color property with get and set. member x.Color with get() = color and set(c) = color <- c // Create a Box instance. let x = Box() // Set and get color values. x.Color <- "blue" printfn "%A" x.Color // Set another value. x.Color <- "red" printfn "%A" x.Color"blue" "red"
This is an operator that returns the System.Type
instance for the specified type. We must place a type name within the angle brackets.
typeof
we get the System.Type
.// A type with one field. type Color() = let mutable Value = null // Get typeof Color type. // ... This is an instance of System.Type. let t = typeof<Color> printfn "%A" tProgram+Color
In F# we can use tuples and records to store data. But for important, often-used information, we use types. This gives us a way to add helpful methods and validation.