Are you a F# programmer that wants to create derived classes or a quick mock object for testing? This excerpt from Chris Smith's Programming F# introduces you to F#'s object expressions.
Interfaces are useful in .NET, but sometimes you just want
an implementation of an interface without going through the hassle of
defining a custom type. For example, in order to sort the elements in a
List<_>, you must provide a type
that implements the IComparer<'a>
interface. As you require more ways to sort that List<_>, you will quickly find your code
littered with types that serve no purpose other than to house the single
method that defines how to compare two objects.
In F#, you can use an object expression, which will create an anonymous class and return an instance of it for you. (The term “anonymous class” just means the compiler will generate the class for you and that you have no way to know its name.) This simplifies the process of creating one-time-use types, much in the same way using a lambda expression simplifies creating one-time-use functions.
The syntax for creating object expressions is a pair of curly braces { }
beginning with the new keyword followed
by the name of an interface, declared just as you would normally use them.
An object expression’s result is an instance of the anonymous
class.
Example 6.3 shows both
using an object expression and an implementation of the IComparer<'a>
interface, which is used to sort items in a collection. Each object
expression defines a different way
to sort a list of names. Without the use of object expressions, this
would take two separate type definitions, each implementing IComparer<'a>. But,
from the use of object expressions, no new explicit types were required.
Example 6.3. Sorting a list using IComparer<'a>
open System.Collections.Generic
type Person =
{ First : string; Last : string }
override this.ToString() = sprintf "%s, %s" this.Last this.First
let people =
new List<_>(
[|
{ First = "Jomo"; Last = "Fisher" }
{ First = "Brian"; Last = "McNamara" }
{ First = "Joe"; Last = "Pamer" }
|] )
let printPeople () =
Seq.iter (fun person -> printfn "\t %s" (person.ToString())) people
// Now sort by last name
printfn "Initial ordering:"
printPeople()
// Sort people by first name
people.Sort(
{
new IComparer with
member this.Compare(l, r) =
if l.First > r.First then 1
elif l.First = r.First then 0
else −1
} )
printfn "After sorting by first name:"
printPeople()
// Sort people by last name
people.Sort(
{
new IComparer with
member this.Compare(l, r) =
if l.Last > r.Last then 1
elif l.Last = r.Last then 0
else −1
} )
printfn "After sorting by last name:"
printPeople()The output in FSI is as follows:
Initial ordering: Fisher, Jomo McNamara, Brian Pamer, Joe After sorting by first name: McNamara, Brian Pamer, Joe Fisher, Jomo After sorting by last name: Fisher, Jomo McNamara, Brian Pamer, Joe
In addition to implementing interfaces, you can also use object expressions to create derived classes. However, types declared in object expressions cannot add any new methods or properties; they can only override abstract members of the base type.
Example 6.4 uses an
object expression to create a new instance of the abstract class
Sandwich, without explicitly
declaring a type.
Example 6.4. Object expressions for creating derived classes
> // Abstract class [] type Sandwich() = abstract Ingredients : string list abstract Calories : int // Object expression for a derived class let lunch = {new Sandwich() withmember this.Ingredients = ["Peanutbutter"; "Jelly"]member this.Calories = 400};; type Sandwich = class abstract member Calories : int abstract member Ingredients : string list new : unit -> Sandwich end val lunch : Sandwich > lunch.Ingredients;; val it : string list = ["Peanutbutter"; "Jelly"]
Object expressions are especially useful when writing unit tests. In unit tests, you typically want to create a mock object, or a class that simulates behavior that is otherwise slow or complicated to isolate, such as mocking out the database connection so your tests don’t hit a real database. Using object expressions, you can easily create anonymous types that can serve as mock objects without the need for defining a plethora of custom types.
With Programming F#, you'll quickly discover the many advantages of Microsoft's new language, which includes access to all the great tools and libraries of the .NET platform. Learn how to reap the benefits of functional programming for your next project -- whether it's quantitative computing, large-scale data exploration, or even a pursuit of your own. F# team member Chris Smith gives you a head start on the fundamentals and advanced concepts of the F# language.




Help









