The next data type that we will look at is a record type. It can be viewed as a tuple with named members (in case of record these are called labels), which can be accessed using a dot-notation and as mentioned earlier it is good to use this type when it would be difficult to understand what the members in a tuple represent. One more difference between a record type and a tuple is that records have to be declared in advance using a type construct:
> // Declaration of a record type
type Product = { Name:string; Price:int };;
> // Constructing a value of the 'Product' type
let p = { Name="Test"; Price=42; };;
val p : Product
> p.Name;; val it : string = "Test"
> // Creating a copy with different 'Name'
let p2 = { p with Name="Test2" };;
val p2 : Product
The last command uses an interesting construct - the with keyword. The record types are by default immutable, meaning that the value of the member can’t be modified. Since the members are immutable you will often need to create a copy of the record value with one (or more) modified members. Doing this explicitly by listing all the members would be impractical, because it would make adding a new members very difficult, so F# supports the with keyword to do this.
F# records are in many ways similar to classes and they can be, indeed, viewed as simplified classes. Record types are by default immutable, which also means that F# use a structural comparison when comparing two values of a record type (instead of the default reference comparison used when working with classes) and if you need this behavior (e.g. for storing records as a keys in a dictionary) it is very practical to use them. Also, using a record instead of a class is a good idea in a functional code where you can use the with construct. Exposing a record type in a public interface of the module requires additional care and it is often useful to make the labels available as members, which makes it easier to modify implementation of the type later. This topic will be further discussed in the third part of this article series.
> // Declaration of a record type
type Product = { Name:string; Price:int };;
> // Constructing a value of the 'Product' type
let p = { Name="Test"; Price=42; };;
val p : Product
> p.Name;; val it : string = "Test"
> // Creating a copy with different 'Name'
let p2 = { p with Name="Test2" };;
val p2 : Product
The last command uses an interesting construct - the with keyword. The record types are by default immutable, meaning that the value of the member can’t be modified. Since the members are immutable you will often need to create a copy of the record value with one (or more) modified members. Doing this explicitly by listing all the members would be impractical, because it would make adding a new members very difficult, so F# supports the with keyword to do this.
F# records are in many ways similar to classes and they can be, indeed, viewed as simplified classes. Record types are by default immutable, which also means that F# use a structural comparison when comparing two values of a record type (instead of the default reference comparison used when working with classes) and if you need this behavior (e.g. for storing records as a keys in a dictionary) it is very practical to use them. Also, using a record instead of a class is a good idea in a functional code where you can use the with construct. Exposing a record type in a public interface of the module requires additional care and it is often useful to make the labels available as members, which makes it easier to modify implementation of the type later. This topic will be further discussed in the third part of this article series.
Post a Comment