So we continue our journey into more of the F# types. This time, we will be looking at Record types.
How Do I Create A Record
When you create a new F# record, it may remind you of anonymous objects in C#. Here is how you create them. I think they are quite similar to anonymous objects in C#, so if you have used C#, F#s records should not be that hard to get into.
It starts by creating a new type for the record. The type definition lists the name of the properties and also the type of the properties. This can be seen below.
Once you have a record type definition, you are free to bind a new instance to a value use Let
. Again, an example of this can be seen below, where we bind a new record using a Let
binding, and we also print the property values of the record instance to the console output.
type Person = { Age : int; Sex: string; Name:string; }
....
....
....
....
let sam = { Age = 12; Sex="Male"; Name ="Sam" }
printfn "let sam = { Age = 12; Sex=\"Male\"; Name=\"Sam\" }"
printfn "Person with Age is %i and Sex is %s and Name is %s" sam.Age sam.Sex sam.Name
which gives this result:
How Do I Alter/Clone A Record
You are able to clone and alter a record, which is typically done as follows:
let sam = { Age = 12; Sex="Male"; Name ="Sam" }
let tom = { sam with Name="Tom" }
printfn "let tom = { sam with Name=\"Tom\" }"
printfn "Person with Age is %i and Sex is %s and Name is %s" tom.Age tom.Sex tom.Name
which gives this result:
Note how we used the “with
” keyword when creating the new tom person
instance. This form of the record expression is called the “copy and update record expression”. Another choice you could use (again, we will be covering this in more detail in a later post) is use a mutable property in your record type. Records are immutable by default; however, you can also explicitly specify a mutable field.
Here is an example, notice how I have created a new type which has a mutable property called MutableName
. By defining a mutable field, I am allowed to update the value of the MutableName
property of the record, which you can do using the “<-
“ operator. Which simply allows a new value to be assigned.
type MutableNamePerson = { Age : int; Sex: string; mutable MutableName:string; }
....
....
....
....
let sam = { Age = 12; Sex="Male"; MutableName ="Sam" }
printfn "let sam = { Age = 12; Sex=\"Male\"; Name=\"Sam\" }"
printfn "Person with Age is %i and Sex is %s and Name is %s" sam.Age sam.Sex sam.MutableName
sam.MutableName <- "Name changed"
printfn "sam.MutableName <- \"Name changed\""
printfn "Person with Age is %i and Sex is %s and Name is %s" sam.Age sam.Sex sam.MutableName
which has this result:
Record Equality
Record types are only equal if ALL the properties are considered the same. Here is an example:
type Person = { Age : int; Sex: string; Name:string; }
....
....
....
....
let someFunction p1 p2 =
printfn "p1=%A, and p2=%A, are they equal %b" p1 p2 (p1=p2)
let sam = { Age = 12; Sex = "Male"; Name = "Sam" }
let john = { Age = 12; Sex = "Male"; Name = "John" }
let april = { Age = 35; Sex = "Female"; Name = "April" }
let sam2 = { Age = 12; Sex = "Male"; Name = "Sam" }
do someFunction sam john
do someFunction sam april
do someFunction sam sam2
And here is the result:
Pattern Matching Records
It is of course possible to use pattern matching (a discussion for another day), which is a core F# technique, to match against Record types. Here is an example:
type Person = { Age : int; Sex: string; Name:string; }
.....
.....
.....
.....
let someFunction (somePerson :Person) =
match somePerson with
| { Name="Sam" } -> printfn "Sam is in the house"
| _ -> printfn "you aint Sam, get outta here clown"
let sam = { Age = 12; Sex="Male"; Name ="Sam" }
let john = { Age = 12; Sex="Male"; Name ="John" }
do someFunction sam
do someFunction john
which has the result:
Methods And Properties
It is also possible to add extra members to records. Here is an example where we add a “Details
” property to allow the full details of the record to be obtained by using a single property (much as we could achieve by overriding the ToString()
method, but more on OO techniques later on ok).
Note that if you tried to add a member to the record type definition as shown in this screen shot, you will get a strange error:
This is easily solved by simply putting the record property definitions on a new line, and making sure the member starts on a new line too, and watch that indenting (whitespace), as it is all important in F#:
type Person =
{ Age : int; Sex: string; Name:string; }
member this.Details = this.Age.ToString() + " " + this.Sex.ToString() + " " + this.Name
....
....
....
....
let sam = { Age = 12; Sex = "Male"; Name = "Sam" }
printfn "sam Details=%s" sam.Details
which has the result: