Jump to content

Introducing F# Object Expressions

+ 1
  adfm's Photo
Posted May 25 2010 03:17 PM

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.

Object Expressions for Interfaces

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

Object Expressions for Derived Classes

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() with

 	member 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.

Cover of Programming F#
Learn more about this topic from Programming F#. 

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.

Learn More Read Now on Safari


Tags:
0 Subscribe


0 Replies