Scala Saturday – The Option Type, Part 2

Last week we introduced the Option type as a way of representing when a function may or may not return a value.

A Collection of One

Another way to think about an Option is as a collection that contains no more than one element. Consequently, Option provides some collection-like semantics, e.g., fold, map, exists, and filter. This allows us to chain operations together without having to check at each step whether the value is Some or None. We can put that off until the end of the sequence of operations and only do the check once. That way, the algorithm is more readable; it’s not cluttered with a bunch of if-else noise.

Say that you have a User type:

case class User(id: String, name: String)

Let’s say that your system is a website. In the top, right corner of the site, you want to display the name of the user who is currently logged in. You need a function that returns the user currently signed in:

val authenticatedUser: () => Option[User] = // ...

Now why would this function return an Option? Well, the user browsing your site may not have logged in at this point. If that’s the case, then the current user is None. So then, the code to get the name of the current user is this:

val nameOpt = authenticatedUser().map(_.name)
// nameOpt: Option[String]

Notice how the type of nameOpt is Option[String]. In other words, assuming that authenticatedUser() returns a Some[User], Scala knows that the User.name property is a String. Nevertheless it propagates the uncertainty, if you will, along through the map operation. Any operations you do on an Option only happen if the Option is a Some. Otherwise, Scala happily ignores the operation and continues to propagate the None.

OK, so now that we have a final result Option, what do we do with it? That’s where Option.getOrElse() comes in:

val name = nameOpt getOrElse "Guest"
// name: String

If nameOpt is a Some, name is the value in the Some. If nameOpt is a None, then name is "Guest". You can test both cases in the Scala REPL. To see it work in the case of a Some:

val authenticatedUser: () => Option[User]  =
    () => Some(User("bcollins", "Brad Collins"))
val name = authenticatedUser()
             .map(_.name)         // Some("Brad Collins")
             .getOrElse("Guest")  // "Brad Collins"
// name: String = Brad Collins

And then to see it with a None:

val authenticatedUser: () => Option[User]  =
    () => None
val name = authenticatedUser()
             .map(_.name)         // None
             .getOrElse("Guest")  // "Guest"
// name: String = Guest

Unraveling the Options

Remember how the collections API defines the flatMap method? For instance, this is the List.flatMap() method:

// signature slightly modified for readability
def flatMap[B](f: (A) ⇒ List[B]): List[B]

It’s like map, but flatMap takes a transformation function that takes an element and returns a list of values rather than just a single value. Then instead of returning a list of lists, flatMap flattens them into a single list.

Option also has a flatMap method. It takes a function that returns an Option and, instead of returning a nested Option (i.e., an Option[Option[B]]), it just returns an Option[B]:

def flatMap[B](f: (A) ⇒ Option[B]): Option[B]

Maybe instead of having an authenticatedUser() function, your app just has a session property. To get the name of the current user, you have to walk the property tree from the application to the session to the user and then finally the name. Application.session is an Option to indicate that there may be no valid session. Session.user is an Option to indicate that there may be no user signed in. Finally, maybe we don’t even force a user to have a name, just a user ID:

case class User(id: String, name: Option[String] = None)
case class Session(user: Option[User] = None)
case class Application(session: Option[Session] = None)

You walk the property tree like this:

val nameOpt = app.session
                .flatMap(_.user)
                .flatMap(_.name)
val name = nameOpt getOrElse "Guest"

Now if any property is None, from session to user to name, nameOpt is None, and name is "Guest".

F# Friday – The Option Type, Part 2

Last week we introduced the Option type as a way of representing when a function may or may not return a value.

A Collection of One

Another way to think about an Option is as a collection that contains no more than one element. Consequently, the Option module provides some collection-like semantics, e.g., fold, map, exists, and even filter in F# 4.0. This allows us to chain operations together without having to check at each step whether the value is Some or None. We can put that off until the end of the sequence of operations and only do the check once. That way, the algorithm is more readable; it’s not cluttered with a bunch of if-else noise.

Say that you have a User type:

type User(id : string, name : string) =
    member x.Id = id
    member x.Name = name

Let’s say that your system is a website. In the top, right corner of the site, you want to display the name of the user who is currently logged in. You need a function that returns the user currently signed in:

let authenticatedUser : unit -> User option = // ...

Now why would this function return an Option? Well, the user browsing your site may not have logged in at this point. If that’s the case, then the current user is None. So then, the code to get the name of the current user is this:

let nameOpt = authenticatedUser()
              |> Option.map (fun u -> u.Name)
// val nameOpt : string option

Notice how the type of nameOpt is string option. In other words, assuming that authenticatedUser() returns a Some<User>, F# knows that the User.Name property is a string. Nevertheless it propagates the uncertainty, if you will, along through the map operation. Any operations you do on an Option only happen if the Option is a Some. Otherwise, F# happily ignores the operation and continues to propagate the None.

OK, so now that we have a final result Option, what do we do with it? That’s where defaultArg comes in:

let name = defaultArg nameOpt "Guest"
// val name : string

If nameOpt is a Some, name is the value in the Some. If nameOpt is a None, then name is "Guest". You can test both cases in the F# REPL. To see it work in the case of a Some:

let authenticatedUser : unit -> User option =
    fun () -> Some(User("bcollins", "Brad Collins"))
let nameOpt = authenticatedUser()
              |> Option.map (fun u -> u.Name)
// val nameOpt : string option = Some "Brad Collins"
let name = defaultArg nameOpt "Guest"
// val name : string = "Brad Collins"

And then to see it with a None:

let authenticatedUser : unit -> User option =
    fun () -> None
let nameOpt = authenticatedUser()
              |> Option.map (fun u -> u.Name)
// val nameOpt : string option = None
let name = defaultArg nameOpt "Guest"
// val name : string = "Guest"

Unraveling the Options

Remember how the collections modules define the collect function? For instance, this is the List.collect() function:

List.collect : ('T -> 'U list) -> 'T list -> 'U list

It’s like map, but collect takes a transformation function that takes an element and returns a list of values rather than just a single value. Then instead of returning a list of lists, collect flattens them into a single list.

Option has a similar function: bind. The bind operation takes a function that returns an Option and, instead of returning a nested Option (i.e., an Option<Option<'U>>, it just returns an Option<'U>:

Option.bind : ('T -> 'U option) -> 'T option -> 'U option

Maybe instead of having an authenticatedUser() function, your app just has a Session property. To get the name of the current user, you have to walk the property tree from the application to the session to the user and then finally the name. App.Session is an Option to indicate that there may be no valid session. Session.User is an Option to indicate that there may be no user signed in. Finally, maybe we don’t even force a user to have a name, just a user ID:

type User(id : string, name : string option) =
    new(id : string) = User(id, None)
    member x.Id = id
    member x.Name = name
type Session(user : User option) = 
    new() = Session(None)
    member x.User = user
type App(session : Session option) =
    new() = App(None)
    member x.Session = session

You walk the property tree like this:

let nameOpt = app.Session
              |> Option.bind (fun s -> s.User)
              |> Option.bind (fun u -> u.Name)
let name = defaultArg nameOpt "Guest"

Now if any property is None, from Session to User to Name, nameOpt is None, and name is "Guest".

Scala Saturday – The Option Type, Part 1

It’s like that time you played basketball in the living room. You knew you should never have done it. But it was just so tempting! And how did that work out for you? Broken lamp? Hole in the wall? And, if you grew up in a house like mine, a tanned hide to follow. You could have avoided it all: the property damage, the wounded pride, the tender backside.

That’s what playing with null is like. You know you shouldn’t, but it’s just so easy! Then you get burned in the end.

The Problem with Null

The problem with null is that it can crop up anywhere an object can. Consider a function that returns a string. This is always OK, right?

val foo: () => String = // ...
val len = foo().length // No worries?

It certainly is in this case:

val foo: () => String = () => "foo"
val len = foo().length
// len: Int = 3

But what about this?

val foo: () => String = () => null
val len = foo().length
// java.lang.NullPointerException !!!

Yeah, not so much. And the problem is that the compiler cannot help us: null is a perfectly legal return value.

We need better semantics! A return type of String ought to guarantee me that I get a String. An empty string would be fine; it just needs to be a String!

Even the guy who invented the concept of null has regretted it:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler.

But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Sir Charles Antony Richard “Tony” Hoare
Turing Award Winner, Inventor of the Quicksort
Null References: The Billion Dollar Mistake (2009)

Fine! All this lamenting that null is a bad idea is great, but don’t you need a way to represent the idea that sometimes a function may not return a result, or at least, not what you would consider a valid result? That’s what Java maps do: If you call Map.get(key), and that map does not contain an entry for key, you get null. Of course, with most maps, null is a legal value, so you don’t know for certain whether null indicates whether the key was not found or the coder explicitly associated null with that key.

There’s got to be a better way!

Option to the Rescue

When you need to represent the idea that a function may not return a result, use Scala’s Option. You can think of an Option as a bucket (pronounced BUCK-et, not boo-KAY):

The Option type illustrated as a bucket. The bucket may be empty or full. If the Option contains a value (represented by the full bucket), we call it "Some." If the Option does not contain a value (represented by the empty bucket), we call it "None."
The Option Type: Is the Bucket Empty or Full?

When a function returns an Option[T], it may contain a value of type T; it may not. You don’t know until you look into it. It’s Schrödinger’s cat! If the Option is empty, we call it None. If it is full, we call it Some.

The advantage of using Option is that now the compiler can help you out. You cannot assign an Option[T] to a variable of type T. Take this example using List.find:

val opt = (1 to 4).toList.find(_ > 5)
val n : int = opt
// error: not found: type int
//        val n : int = opt

So then, you cannot forget and accidentally assign a null, only to have it bite you later. The compiler reminds you that you need to test the result before trying to use it:

val ns = (1 to 4).toList

val none = ns.find(_ > 5)

if (none.isEmpty) {
  println("None found greater than 5")
} else {
  println(s"Found one greater than 5: ${none.get}")
}
// None found greater than 5

val some = ns.find(_ < 5)
if (some.isEmpty) {
  println("None found less than 5")
} else {
  println(s"Found one less than 5: ${some.get}")
}
// Found one less than 5: 1

Of course, you can override the safeguard, but at least then, you cannot claim ignorance:

val ns = (1 to 4).toList
val none = ns.find(_ > 5)
println(s"Found one greater than 5: ${none.get}")
// java.util.NoSuchElementException: None.get !!!

Next week, we will look at Option some more to see how we can use it in a more functional fashion.

F# Friday – The Option Type, Part 1

It’s like that time you played basketball in the living room. You knew you should never have done it. But it was just so tempting! And how did that work out for you? Broken lamp? Hole in the wall? And, if you grew up in a house like mine, a tanned hide to follow. You could have avoided it all: the property damage, the wounded pride, the tender backside.

That’s what playing with null is like. You know you shouldn’t, but it’s just so easy! Then you get burned in the end.

The Problem with Null

The problem with null is that it can crop up anywhere an object can. Consider a function that returns a string. This is always OK, right?

let foo : unit -> string = // ...
let len = foo().Length // No worries?

It certainly is in this case:

let foo : unit -> string = fun () -> "foo"
let len = foo().Length
// val len : int = 3

But what about this?

let foo : unit -> string = fun () -> null
let len = foo().Length
// System.NullReferenceException:
//   Object reference not set to an instance 
//   of an object.

Yeah, not so much. And the problem is that the compiler cannot help us: null is a perfectly legal return value.

We need better semantics! A return type of string ought to guarantee me that I get a string. An empty string would be fine; it just needs to be a string!

Even the guy who invented the concept of null has regretted it:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler.

But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Sir Charles Antony Richard “Tony” Hoare
Turing Award Winner, Inventor of the Quicksort
Null References: The Billion Dollar Mistake (2009)

Fine! All this lamenting that null is a bad idea is great, but don’t you need a way to represent the idea that sometimes a function may not return a result, or at least, not what you would consider a valid result? That’s what Java does: If you call Map.get(key), and that map does not contain an entry for key, you get null. As we saw couple of weeks ago, F#’s List.find (and the other collections’ find functions, too) is not any more elegant: It throws an exception!

There’s got to be a better way!

Option to the Rescue

When you need to represent the idea that a function may not return a result, use F#’s Option. You can think of an Option as a bucket (pronounced BUCK-et, not boo-KAY):

The Option type illustrated as a bucket. The bucket may be empty or full. If the Option contains a value (represented by the full bucket), we call it "Some." If the Option does not contain a value (represented by the empty bucket), we call it "None."
The Option Type: Is the Bucket Empty or Full?

When a function returns an Option<'T>, it may contain a value of type T; it may not. You don’t know until you look into it. It’s Schrödinger’s cat! If the Option is empty, we call it None. If it is full, we call it Some.

The advantage of using Option is that now the compiler can help you out. You cannot assign an Option<'T> to a variable of type T. Take this example using List.tryFind:

let opt = [1..4] |> List.tryFind (fun n -> n > 5)
let n : int = opt
//   let n : int = opt;;
//   --------------^^^
// 
// This expression was expected to have type
//     int    
// but here has type
//     int option

So then, you cannot forget and accidentally assign a null, only to have it bite you later. The compiler reminds you that you need to test the result before trying to use it:

let ns = [1..4]

let none = ns |> List.tryFind (fun n -> n > 5)
if none.IsSome then
    printfn "Found one greater than 5: %d" none.Value
else
    printfn "None found greater than 5"
// None found greater than 5

let some = ns |> List.tryFind (fun n -> n < 5)
if some.IsSome then
    printfn "Found one less than 5: %d" some.Value
else
    printfn "None found less than 5"
// Found one less than 5: 1

Of course, you can override the safeguard, but at least then, you cannot claim ignorance:

let ns = [1..4]
let none = ns |> List.tryFind (fun n -> n > 5)
printfn "Found one greater than 5: %d" none.Value
// System.NullReferenceException:
//   Object reference not set to an instance 
//   of an object.

Next week, we will look at Option some more to see how we can use it in a more functional fashion.

Scala Saturday – The partition Method

The filter function takes a collection and a predicate and returns only the items in a collection that meet the predicate. It discards the ones that don’t.

Well, what if you want to retain all the items in the collection, but you just want them separated into two groups–the sheep from goats, as it were? That’s where partition comes in. The partition operation takes a collection and a predicate, just as filter does, but instead of tossing the items that don’t meet the predicate, partition returns a second collection along with the first: one containing all the items that meet the predicate and one containing all the rest.

Maybe you run a business, and once per quarter, you want to send a message to all your customers. You send a thank you note to the customers that have made a purchase in the last quarter. To the customers who have not, you send a we-miss-you note, perhaps containing a coupon. So then, you need to partition your customer list:

A list of customers, each with a lastPurchase field that is the date of the customer's last purchase, partitioned into two lists. The first list is all customers who have made a purchase in the last three months while the other list contains customers who have not made a purchase in the last three months.
Partitioning a List of Customers Based on the Date of the Latest Purchase

Here is the Customer case class (which uses Java 8’s new LocalDate class):

case class Customer(
  name: String,
  email: String,
  latestPurchase: LocalDate)

Now given a list of customers, here is how you partition that list into those who have made recent purchases and those who have not:

val customers = List(
  Customer("Bob", "bob@bob.com", LocalDate.of(2015, Month.JUNE, 5)),
  Customer("Barb", "barb@barbara.com", LocalDate.of(2015, Month.MAY, 15)),
  Customer("Chuck", "chuck@charles.com", LocalDate.of(2015, Month.JANUARY, 26)),
  Customer("Charlie", "charlie@charlotte.com", LocalDate.of(2015, Month.MARCH, 1)),
  Customer("Dan", "dan@dan.com", LocalDate.of(2014, Month.DECEMBER, 21)),
  Customer("Deb", "deb@deborah.com", LocalDate.of(2015, Month.JANUARY, 24)),
  Customer("Ed", "ed@theodore.com", LocalDate.of(2015, Month.MARCH, 15)),
  Customer("Elle", "elle@elle.com", LocalDate.of(2015, Month.JUNE, 15))
)

val threeMosAgo = LocalDate.now.minusMonths(3)
val (recent, distant) = customers.partition {
  c => c.latestPurchase.isAfter(threeMosAgo)
}
// recent: List[Customer] = List(
//   Customer(Bob,bob@bob.com,2015-06-05),
//   Customer(Barb,barb@barbara.com,2015-05-15), 
//   Customer(Elle,elle@elle.com,2015-06-15))
// distant: List[Customer] = List(
//   Customer(Chuck,chuck@charles.com,2015-01-26),
//   Customer(Charlie,charlie@charlotte.com,2015-03-01),
//   Customer(Dan,dan@dan.com,2014-12-21),
//   Customer(Deb,deb@deborah.com,2015-01-24),
//   Customer(Ed,ed@theodore.com,2015-03-15))

Now you can send that thank you note to each of the customers in the recent list and a miss-you note to each customer in the distant list.

F# Friday – The partition Function

The filter function takes a collection and a predicate and returns only the items in a collection that meet the predicate. It discards the ones that don’t.

Well, what if you want to retain all the items in the collection, but you just want them separated into two groups–the sheep from goats, as it were? That’s where partition comes in. The partition operation takes a collection and a predicate, just as filter does, but instead of tossing the items that don’t meet the predicate, partition returns a second collection along with the first: one containing all the items that meet the predicate and one containing all the rest.

Maybe you run a business, and once per quarter, you want to send a message to all your customers. You send a thank you note to the customers that have made a purchase in the last quarter. To the customers who have not, you send a we-miss-you note, perhaps containing a coupon. So then, you need to partition your customer list:

A list of customers, each with a LastPurchase field that is the date of the customer's last purchase, partitioned into two lists. The first list is all customers who have made a purchase in the last three months while the other list contains customers who have not made a purchase in the last three months.
Partitioning a List of Customers Based on the Date of the Latest Purchase

Here is the Customer type:

type Customer(name : string, email : string, latestPurchase : DateTime) =
    member x.Name = name
    member x.Email = email
    member x.LatestPurchase = latestPurchase
    override x.ToString() = 
        latestPurchase.ToString("dd MMM yyyy")
        |> sprintf "Customer(%s, %s, %s)" name email

Now given a list of customers, here is how you partition that list into those who have made recent purchases and those who have not:

let customers = [
    Customer("Bob", "bob@bob.com", DateTime.Parse "5 Jun 2015")
    Customer("Barb", "barb@barbara.com", DateTime.Parse "15 May 2015")
    Customer("Chuck", "chuck@charles.com", DateTime.Parse "26 Jan 2015")
    Customer("Charlie", "charlie@charlotte.com", DateTime.Parse "1 Mar 2015")
    Customer("Dan", "dan@dan.com", DateTime.Parse "21 Dec 2014")
    Customer("Deb", "deb@deborah.com", DateTime.Parse "24 Jan 2015")
    Customer("Ed", "ed@theodore.com", DateTime.Parse "15 Mar 2015")
    Customer("Elle", "elle@elle.com", DateTime.Parse "15 Jun 2015")
]

let threeMosAgo = DateTime.Now.AddMonths -3
let recent, distant =
    customers
    |> List.partition (fun c -> c.LatestPurchase > threeMosAgo)
// val recent : Customer list =
//   [Customer(Bob, bob@bob.com, 05 Jun 2015);
//    Customer(Barb, barb@barbara.com, 15 May 2015);
//    Customer(Elle, elle@elle.com, 15 Jun 2015)]
// val distant : Customer list =
//   [Customer(Chuck, chuck@charles.com, 26 Jan 2015);
//    Customer(Charlie, charlie@charlotte.com, 01 Mar 2015);
//    Customer(Dan, dan@dan.com, 21 Dec 2014);
//    Customer(Deb, deb@deborah.com, 24 Jan 2015);
//    Customer(Ed, ed@theodore.com, 15 Mar 2015)]

Now you can send that thank you note to each of the customers in the recent list and a miss-you note to each customer in the distant list.

Scala Saturday – The find Method

The Scala collections all define the find function. The find operation traverses a collection and returns the first item in the collection that meets the given condition(s).

Perhaps you are a teacher. You have a type that represents a student with a name and a grade:

case class Student(name: String, grade: Int)

And you have a randomized list of those students:

val students = List(
  Student("Sally", 79),
  Student("Giedrius", 81),
  Student("Aryana", 98),
  Student("Ty", 94),
  Student("Eloise", 86),
  Student("Vergil", 89),
  Student("Doug", 66),
  Student("Delmar", 77),
  Student("Makenna", 88),
  Student("Orval", 93) )

Maybe you want to reward a random A-student (i.e., a student with a grade of 90 or above) with a candy bar. You can use find to return the first A-student in the list:

val scholar = students.find(_.grade >= 90)
// scholar: Option[Student] =
//   Some(Student(Aryana,98))

So, that’s great: Aryana gets a Twix! (It is the only one with the cookie crunch, after all.)

Notice, by the way, that scholar is not a Student, but rather an Option that contains a Student. Let’s get back to that in a minute.

You also happen to be one of those sadistic teachers, though, who likes to embarrass the students who are not living up to their potential. Therefore you pick a random F-student (i.e., with a grade less than 65) and outfit him/her with a dunce cap:

val dunce = students.find(_.grade < 65)
// dunce: Option[Student] = None

Isn’t that interesting? There are no F-students. (Who’s the dunce now?)

That’s the beauty of find: it returns an Option instead of the bare Student. Therefore if no item in the list meets find’s predicate, it does not throw an exception or return null (the way some other languages do). It just returns None. That way, if you write something like this in which you specify that you expect the Student type, Scala does not let you get away with it:

val dunce: Student = students.find(_.grade < 65)
// error: type mismatch;
//  found   : Option[Student]
//  required: Student
//        val dunce: Student = students.find(_.grade < 65)
//                                          ^

It warns you at compile time that you are aiming a firearm at your foot instead of letting you shoot it off at run time with one exception or another.

It could be that you give a test next week that slays the entire class: you may not have an A-student that week. The Option value that find returns makes you test dunce and scholar before you use them to make sure someone is supposed to get a candy bar or a dunce cap before you start handing them out.

F# Friday – The find and tryFind Functions

The F# collections modules define the find function. The find operation traverses a collection and returns the first item in the collection that meets the given condition(s).

Perhaps you are a teacher. You have a type that represents a student with a name and a grade:

type Student(name: string, grade: int) =
    member x.Name = name
    member x.Grade = grade
    override x.ToString() =
        sprintf "(%s, %d)" name grade

And you have a randomized list of those students:

let students = [ Student("Sally", 79);
                 Student("Giedrius", 81);
                 Student("Aryana", 98);
                 Student("Ty", 94);
                 Student("Eloise", 86);
                 Student("Vergil", 89);
                 Student("Doug", 66);
                 Student("Delmar", 77);
                 Student("Makenna", 88);
                 Student("Orval", 93) ]

Maybe you want to reward a random A-student (i.e., a student with a grade of 90 or above) with a candy bar. You can use find to return the first A-student in the list:

let scholar = students 
               |> List.find (fun s -> s.Grade >= 90)
// val scholar : Student = (Aryana, 98)

So, that’s great: Aryana gets a Twix! (It is the only one with the cookie crunch, after all.)

You also happen to be one of those sadistic teachers, though, who likes to embarrass the students who are not living up to their potential. Therefore you pick a random F-student (i.e., with a grade less than 65) and outfit him/her with a dunce cap:

let dunce = students 
            |> List.find (fun s -> s.Grade < 65)

// An unhandled exception of type 
// 'System.Collections.Generic.KeyNotFoundException'
// occurred in FSharp.Core.dll

Whoa! Exception? Where did that come from? (Who’s the dunce now?)

That’s a shortcoming of find. If no element meets the condition, find throws an exception.

Enter tryFind. The tryFind function returns an Option. Even on an empty collection, tryFind does not throw an exception.

let dunceOpt = students 
               |> List.tryFind (fun s -> s.Grade < 65)
// val dunceOpt : Student option = None

Of course, you may give a test one week that slays the entire class: you may not have an A-student that week. You’d better use tryFind to find an A-student, too:

let scholarOpt =
    students 
    |> List.tryFind (fun s -> s.Grade >= 90)
// val scholarOpt : Student option =
//   Some (Aryana, 98)

Now you can test dunceOpt and scholarOpt before you use them to make sure someone is supposed to get a candy bar or a dunce cap before you start handing them out.

Scala Saturday – The sorted, sortBy, and sortWith Methods

You don’t have to program for very long before you need to sort a list of things. Scala’s collections modules are nice enough to give you a canned sorted method.

Maybe you have a list of words, and you want to sort them:

val xs = List(
  "Our", "fathers", "trusted", "in", "You",
  "They", "trusted", "and", "You",
  "delivered", "them")
val sorted = xs.sorted
// sorted: List[String] =
//   List(Our, They, You, You, and,
//        delivered, fathers, in, them,
//        trusted, trusted)

Easy enough. But isn’t that interesting? ‘Y’ words come before ‘A’ words. Or rather, more correctly, ‘Y’ words come before ‘a’ words because, by default, all capital letters are sorted before lowercase letters. And that’s all that sorted does for you: It sorts using the default ordering.

Wouldn’t it be great if you could alter what sort uses to sort by? Well, you can: Use sortBy.

Here’s how to sort this list of words the way your 2nd-grade teacher taught you, that is, without respect to case. Pass sortBy a lambda that returns the lowercase version of each string:

val sortedCaseInsensitive =
  xs.sortBy(_.toLowerCase)
// sortedCaseInsensitive: List[String] =
//   List(and, delivered, fathers, in,
//        Our, them, They, trusted, trusted,
//        You, You)

Or maybe you need to sort a list of words in order of length. Employ a lambda that returns the length of each word:

val sortedByLength = xs.sortBy(_.length)
// sortedByLength: List[String] = 
//   List(in, Our, You, and, You, They,
//        them, fathers, trusted, trusted,
//        delivered)

The sortBy method also works really well for classes. You can use sortBy to specify which member or combination of members to sort by.

Maybe you have a class for album tracks. It has two members: track length (in minutes) and track title.

case class Track(length : Double, name : String)

Let’s say that you have the tracks of Genesis’s Foxtrot:

val ts = List(
  Track(7.35, "Watcher of the Skies"),
  Track(4.783, "Time Table"),
  Track(8.583, "Get 'Em Out by Friday"),
  Track(5.75, "Can-Utility and the Coastliners"),
  Track(1.65, "Horizons"),
  Track(22.95, "Supper's Ready") )

Sort the tracks by track length by passing a lambda to sortBy that returns the length of each track:

val sortedByTrackLength = ts.sortBy(_.length)
// sortedByTrackLength: List[Track] = List(
//   Track(1.65,Horizons),
//   Track(4.783,Time Table), 
//   Track(5.75,Can-Utility and the Coastliners), 
//   Track(7.35,Watcher of the Skies), 
//   Track(8.583,Get 'Em Out by Friday), 
//   Track(22.95,Supper's Ready))

To sort according to track name instead, use a lambda that returns the track name rather than track length:

val sortedByTrackName = ts.sortBy(_.name)
// sortedByTrackName: List[Track] = List(
//   Track(5.75,Can-Utility and the Coastliners), 
//   Track(8.583,Get 'Em Out by Friday), 
//   Track(1.65,Horizons), 
//   Track(22.95,Supper's Ready), 
//   Track(4.783,Time Table), 
//   Track(7.35,Watcher of the Skies))

Another sorting method is sortWith. It differs from sortBy in the kind of lambda that it takes to perform the sorting. Whereas sortBy accepts a function that takes a single element and generates a single value to sort by, sortWith accepts a function that takes two elements as inputs and returns true if the first element is “less than” the second element, or otherwise false. In other words, you define the pairwise comparison.

For example, if you want to sort your list of words from Psalm 22 in reverse, you could do so with sortWith by reversing the comparison—do a greater-than comparison rather than a less-than:

val reversed = xs.sortWith(_ > _)
// reversed: List[String] = List(
//   trusted, trusted, them, in, fathers, 
//   delivered, and, You, You, They, Our)

sortWith is very nice when you need to compare more than one object member. Perhaps you need to sort a list of names according to last name and then first name. The lambda can first compare the last names and then the first names only if necessary:

case class Name(first: String, last: String)
val names = List(
  Name("Phil", "Collins"),
  Name("Jackie", "Collins"),
  Name("Joan", "Collins"),
  Name("Tom", "Collins"),
  Name("George", "Bush"),
  Name("Jeb", "Bush"),
  Name("Neil", "Bush"),
  Name("Marvin", "Bush"))

val lastThenFirst = names.sortWith { (a, b) =>
  if (a.last == b.last) a.first < b.first
  else a.last < b.last
}
// lastThenFirst: List[Name] = List(
//   Name(George,Bush), 
//   Name(Jeb,Bush), 
//   Name(Marvin,Bush), 
//   Name(Neil,Bush), 
//   Name(Jackie,Collins), 
//   Name(Joan,Collins), 
//   Name(Phil,Collins), 
//   Name(Tom,Collins))

F# Friday – The sort and sortBy Functions

You don’t have to program for very long before you need to sort a list of things. F#’s collections modules are nice enough to give you a canned sort function.

Maybe you have a list of words, and you want to sort them:

let xs =
  [
    "To"; "be"; "or"; "not"; "to"; "be";
    "That"; "is"; "the"; "question"
  ]
let sorted = List.sort xs
// val sorted : string list =
//   ["That"; "To"; "be"; "be"; "is"; "not"; 
//    "or"; "question"; "the"; "to"]

Easy enough. But isn’t that interesting? ‘T’ words come before ‘B’ words. Or rather, more correctly, ‘T’ words come before ‘b’ words because, by default, all capital letters are sorted before lowercase letters. And that’s all that sort does for you: It sorts using the default sorting mechanism.

Wouldn’t it be great if you could alter what sort uses to sort by? Well, you can: Use sortBy.

Here’s how to sort this list of words the way your 2nd-grade teacher taught you, that is, without respect to case. Pass sortBy a lambda that returns the lowercase version of each string:

let sortedCaseInsensitive =
  xs |> List.sortBy (fun x -> x.ToLower())
// val sortedCaseInsensitive : string list =
//   ["be"; "be"; "is"; "not"; "or";
//    "question"; "That"; "the"; "To"; "to"]

Or maybe you need to sort a list of words in order of length. Employ a lambda that returns the length of each word:

let sortedByLength =
  xs |> List.sortBy (fun x -> x.Length)
// val sortedByLength : string list =
//   ["To"; "be"; "or"; "to"; "be"; "is";
//    "not"; "the"; "That"; "question"]

The sortBy function also works really well for classes and record types. You can use sortBy to specify which member or combination of members to sort by.

Maybe you have a record type for album tracks. It has two members: track length (in minutes) and track title.

type Track = { Length : float; Name : string }

Let’s say that you have the tracks of Spock’s Beard’s V:

let ts =
  [ { Length = 16.467; 
      Name = "At the End of the Day" };
    { Length = 6.083; 
      Name = "Revelation" };
    { Length = 4.65; 
      Name = "Thoughts (Part II)" };
    { Length = 4.067; 
      Name = "All on a Sunday" };
    { Length = 4.65; 
      Name = "Goodbye to Yesterday" };
    { Length = 27.03; 
      Name = "The Great Nothing" } ]

Sort the tracks by track length by passing a lambda to sortBy that returns the length of each track:

let sortedByTrackLength =
  ts |> List.sortBy (fun t -> t.Length)
// val sortedByTrackLength : Track list =
//   [{Length = 4.067;
//     Name = "All on a Sunday";};
//    {Length = 4.65;
//     Name = "Thoughts (Part II)";};
//    {Length = 4.65;
//     Name = "Goodbye to Yesterday";};
//    {Length = 6.083;
//     Name = "Revelation";};
//    {Length = 16.467;
//     Name = "At the End of the Day";};
//    {Length = 27.03;
//     Name = "The Great Nothing";}]

To sort according to track name instead, use a lambda that returns the track name rather than track length:

let sortedByTrackName =
  ts |> List.sortBy (fun t -> t.Name)
// val sortedByTrackName : Track list =
//   [{Length = 4.067;
//     Name = "All on a Sunday";};
//    {Length = 16.467;
//     Name = "At the End of the Day";};
//    {Length = 4.65;
//     Name = "Goodbye to Yesterday";};
//    {Length = 6.083;
//     Name = "Revelation";};
//    {Length = 27.03;
//     Name = "The Great Nothing";};
//    {Length = 4.65;
//     Name = "Thoughts (Part II)";}]