Categories
Tech

Scala Saturday – Pattern Matching, Part 2: Case Classes

In addition to regular classes, Scala also provides case classes for the purpose of pattern matching. They offer a few benefits that standard classes do not.

Getting Personal

Defining a case class is stupid easy:

case class Person(first: String, last: String)

Person has two fields, first and last, both of type string. Notice that the parameters don’t need a val keyword.

Defining a Person variable is even easier than a standard class because you can omit the new keyword:

val me = Person("Brad", "Collins")

Pattern matching on case class instances is pretty straightforward, too:

def greet(p : Person) = p match {
  case Person("Brad", "Collins") => "It's me!"
  case Person("Brad", _) => "Nice name"
  case Person(_, "Collins") => "Greetings, kinfolk"
  case _ => "Hello, stranger"
}

val me = Person("Brad", "Collins")
val kin = Person("Shad", "Collins")
val namesake = Person("Brad", "Rollins")
val stranger = Person("Ezra", "Shemiah")

val meGreeting = greet(me)
// meGreeting: String = It's me!

val kinGreeting = greet(kin)
// kinGreeting: String = Greetings, kinfolk

val namesakeGreeting = greet(namesake)
// namesakeGreeting: String = Nice name

val strangerGreeting = greet(stranger)
// strangerGreeting: String = Hello, stranger

To match on a Person object with specific first and last fields, specify both of them, as in the first match case above. To match on just one field, either first or last, specify the field to match, and use the wildcard pattern, the underscore (_), for the field you don’t care about, as in the second and third match cases above. If Person had more than two fields, you could match any subset of them by specifying the field values you need to be exact and using the wildcard pattern for the fields you don’t.

One other thing to note here: Order matters. What if you had defined greet this way?

def greet(p : Person) = p match {
  case Person("Brad", _) => "Nice name"
  case Person(_, "Collins") => "Greetings, kinfolk"
  case Person("Brad", "Collins") => "It's me!" // OOPS!
  case _ => "Hello, stranger"
}

The third case (line 4 above) would never match because Person("Brad", "Collins") would always match the first case. So, pay attention out there.

Personal Improvement

As with regular classes, we can add member functions and properties to the case class itself and also put some things in a companion object:

case class Person(first: String, last: String) {
  def swap = Person(last, first)
}
object Person {
  val anonymous = Person("", "")
}

val me = Person("Brad", "Collins")
// me: Person = Person(Brad,Collins)

val swapped = me.swap
// swapped: Person = Person(Collins,Brad)

val johnDoe = Person.anonymous
// johnDoe: Person = Person(,)

This example also demonstrates one of the extras you get with class classes: A toString() implementation. With a regular class, if you want toString() to show you something more descriptive than a type name, you have to overload toString() yourself.

Case classes also throw in implementations of equals(o) and hashCode() for no charge:

val me = Person("Brad", "Collins")
val swapped = me.swap
val myself = Person("Brad", "Collins")

val iAm = me == myself
// iAm: Boolean = true

val iAint = me == swapped
// iAint: Boolean = false

val meHash = me.hashCode()
// meHash: Int = 777586888

val myselfHash = myself.hashCode()
// myselfHash: Int = 777586888

val swappedHash = swapped.hashCode()
// swappedHash: Int = 1042444723

Notice how me and myself are equal though they are different object instances, and they also have the same hash code.

Finally, if you have a case class instance and need a new instance with, say, only one or two field values that are different, case classes throw in the copy() to do just that so that you don’t have to set every field value explicitly:

val me = Person("Brad", "Collins")
val kin = me.copy(first = "Shad")
// kin: Person = Person(Shad,Collins)

val namesake = me.copy(last = "Rollins")
// namesake: Person = Person(Brad,Rollins)

Personable Companions

The way case classes perform some of their magic is that Scala defines a companion object for each case class behind the scenes.

First, why don’t you need the new keyword when instantiating case classes? Because the companion object has an apply() method that takes the parameters defined in the case class constructor:

case class Person(first: String, last: String)
// Notional representation of what the
// compiler provides:
//
// object Person {
//   def apply(first: String, last: String) =
//     new Person(first, last)
// 
//   def unapply(p: Person): Option[String, String] =
//     Some(p.first, p.last)
// }

val me = Person("Brad", "Collins")
// Actually calls ...
// Person.apply("Brad", "Collins")

That unapply() method is how Scala destructures case classes when pattern matching. When you write this:

p match {
  case Person(f,l) => ...
}

… Scala uses Person.unapply(p) to populate the f and l variables.

One final note: When we added the anonymous field to the Person companion object above, the compiler was nice enough to merge that with the one it generated for us instead of overwriting the generated one with ours.

Watch out if you attempt to type that out into the REPL, you do overwrite the compiler-generated Person companion object. (Hint: Use the REPL’s :paste function to get around that.)

Categories
Tech

F# Friday – Pattern Matching, Part 2: Record Types

In addition to classes, F# also provides record types. They offer a few benefits that standard classes do not.

Getting Personal

Defining a record type is straightforward:

type Person = { First : string; Last : string }

Person has two fields, First and Last, both of type string. Defining a Person variable is easy:

let me = { First = "Brad"; Last = "Collins" }

Pattern matching on record objects is pretty straightforward, too:

let greet = 
    function
    | { First = "Brad"; Last = "Collins" } ->
        "It's me!"
    | { First = "Brad" } -> "Nice name"
    | { Last = "Collins" } -> "Greetings, kinfolk"
    | _ -> "Hello, stranger"

let me = { First = "Brad"; Last = "Collins" }
let kin = { First = "Shad"; Last = "Collins" }
let namesake = { First = "Brad"; Last = "Rollins" }
let stranger = { First = "Ezra"; Last = "Shemiah" }

let meGreeting = greet me
// val meGreeting : string = "It's me!"

let kinGreeting = greet kin
// val kinGreeting : string = "Greetings, kinfolk"

let namesakeGreeting = greet namesake
// val namesakeGreeting : string = "Nice name"

let strangerGreeting = greet stranger
// val strangerGreeting : string = "Hello, stranger"

First, notice that you do not have to tell greet what kind of record type you want to match on. F# infers it.

Next, to match on a Person record with specific First and Last fields, specify both of them, as in the first match case above. To match on just one field, either First or Last, specify the field to match, and use the wildcard pattern, the underscore (_), for the field you don’t care about, as in the second and third match cases above. If Person had more than two fields, you could match any subset of them by specifying the field values you need to be exact and using the wildcard pattern for the fields you don’t.

One other thing to note here: Order matters. What if you had defined greet this way?

let greet = 
    function
    | { First = "Brad" } -> "Nice name"
    | { Last = "Collins" } -> "Greetings, kinfolk"
    | { First = "Brad"; Last = "Collins" } ->
        "It's me!" // OOPS!
    | _ -> "Hello, stranger"

The third case (lines 5 and 6 above) would never match because { First = "Brad"; Last = "Collins" } would always match the first case. So, pay attention out there.

Personal Improvement

As with classes, we can extend record types with member functions and properties:

type Person = { 
    First : string
    Last : string
}
with
    static member Anonymous = { First = ""; Last = "" }
    static member Create first last = 
        { First = first
          Last = last }
    member x.Swap () = Person.Create x.Last x.First

let me = Person.Create "Brad" "Collins"
// val me : Person = {First = "Brad";
//                    Last = "Collins";}

let swapped = me.Swap()
// val swapped: Person = {First = "Collins";
//                        Last = "Brad";}

This example also demonstrates one of the extras you get with record types: A ToString() implementation. With a regular class, if you want ToString() to show you something more descriptive than a type name, you have to overload System.Object.ToString() yourself.

Record types also throw in implementations of Equals(o) and GetHashCode() for no charge:

let me = Person.Create "Brad" "Collins"
let swapped = me.Swap()
let myself = Person.Create "Brad" "Collins"

let iAm = me = myself
// val iAm : bool = true

let iAint = me = swapped
// val iAint : bool = false

let meHash = me.GetHashCode()
// val meHash : int = 1825427853

let myselfHash = myself.GetHashCode()
// val myselfHash : int = 1825427853

let swappedHash = swapped.GetHashCode()
// val swappedHash : int = 39593589

Notice how me and myself are equal though they are different object instances, and they also have the same hash code.

Finally, if you have a record instance and need a new instance with, say, only one or two field values that are different, F# provides a way to do that using the with keyword so that you don’t have to set every field value explicitly:

let me = Person.Create "Brad" "Collins"
let kin = { me with First = "Shad" }
// val kin : Person = {First = "Shad";
//                     Last = "Collins";}

let namesake = { me with Last = "Rollins" }
// val namesake : Person = {First = "Brad";
//                          Last = "Rollins";}

Identity Crisis

But what happens when you have two record types that coincidentally have the same members? Maybe you have a type representing polar coordinates type and a type representing an arc. Both of them contain a radius member, R, and an angle member, Θ:

type Polar = { R : float; Ï´ : float }
type Arc = { R : float; Ï´ : float }

What happens when you want to calculate the length of an arc, and you want to constrain arcs to “valid” angles, that is, between zero and a whole circle, nothing more than a circle or negative?

let π = System.Math.PI

let length arc =
    match arc with
    | { ϴ = a } when a < 0.0 || (2.0 * π) < a ->
        raise <| System.ArgumentException "Ï´ is out of range"
    | { R = radius; Ï´ = angle } -> radius * angle

F# yields a warning:

The field labels and expected type of this record expression or pattern do not uniquely determine a corresponding record

In other words, F# doesn’t know whether you want to match on a Polar object or an Arc object. You can fix this a couple of ways. One way is to specify the type of the arc parameter:

let π = System.Math.PI

let length (arc : Arc) =
    match arc with
    | { ϴ = a } when a < 0.0 || (2.0 * π) < a ->
        raise <| System.ArgumentException "Ï´ is out of range"
    | { R = radius; Ï´ = angle } -> radius * angle

let quarter = { R = 2.5; Ï´ = (Ï€ / 2.0) }
let len = length quarter
// val len : float = 3.926990817

Another option is to prepend the Θ field in the match expression with the Arc type:

let π = System.Math.PI

let length arc =
    match arc with
    | { Arc.ϴ = a } when a < 0.0 || (2.0 * π) < a ->
        raise <| System.ArgumentException "Ï´ is out of range"
    | { R = radius; Ï´ = angle } -> radius * angle

let quarter = { R = 2.5; Ï´ = (Ï€ / 2.0) }
let len = length quarter
// val len : float = 3.926990817

Similarly, to remove any ambiguity when creating a record instance, prepend the type name to the beginning of one of the field names:

let π = System.Math.PI

let arc = { Arc.R = 2.5; Ï´ = (Ï€ / 2.0) }
let polar = { Polar.R = 1.75; ϴ = (1.25 * π) }
Categories
Tech

Scala Saturday – Pattern Matching, Part 1

A terribly useful technique in functional programming is pattern matching. Pattern matching is simply a form of conditional logic, like an if-else expression or (in other languages) a switch statement, but quite a bit more powerful and flexible. With pattern matching, you can perform matches and take action based on simple values, such as integers, but also on complex types and the values of their members. Here are some examples using the simpler types, and a future post(s) will illustrate how to match on more complex types.

On the Whole (Numbers)

Pattern matching on integers is very straightforward. Just use literals:

def getResponse(talents: Int) = talents match {
  case 5 => "Here are your five talents plus five more"
  case 2 => "Here are your two talents plus two more"
  case 1 => "Here is your one talent, which I hid"
  case _ => "Uh, wrong story"
}

val response = getResponse(5)
// response: String = 
//   Here are your five talents plus five more

val apocryphal = getResponse(42)
// apocryphal: String = Uh, wrong story

Of course, the set of all possible integers is very large. Our example here only covers three specific values: 1, 2, and 5. To cover every other case that you don’t specify explicitly, use the wildcard pattern _, the underscore. That’s how we could handle 42. Or 103. Or −7. Or any other integer.

Getting to the (Floating) Point

Floating point numbers are difficult to pin down because of the margin of error, so you don’t typically match on a specific number. Usually you match on ranges. Pattern matching allows for that, too:

def getState(temp: Double) = temp match {
  case x if x <= 32.0 => "solid"
  case x if x >= 212.0 => "gas"
  case _ => "liquid"
}

val atRoomTemp = getState(70.0)
// atRoomTemp: String = liquid

val atSouthPole = getState(-70.6)
// atSouthPole: String = solid

Putting a condition on a match with the if keyword like that is called a guard. Guards are simply Boolean expressions. You could alternatively write the “liquid” step in getState with a compound Boolean expression:

def getState2(temp: Double) = temp match {
  case x if 32.0 > x && x < 212.0 => "liquid"
  case x if x >= 212.0 => "gas"
  case _ => "solid"
}
  
val onHotSummerDay = getState2(98.5)
// onHotSummerDay: String = solid

In one more rewrite of getState, note that it is possible to use variables, not just literals, in guards:

def getState3(temp: Double) = {
  val freezingPoint = 32.0
  val boilingPoint = 212.0
  temp match {
    case x if x <= freezingPoint => "solid"
    case x if x >= boilingPoint => "gas"
    case _ => "liquid"
  }
}

val inDeathValley = getState3(134.0)
// inDeathValley: String = liquid

Stringly Typed Interfaces

Perhaps your application executes commands, and those commands are specified by names, that is, strings. (Some folks jokingly call them “stringly typed interfaces.”) Pattern matching is perfect for this task:

def execute(command: String, id: Int, value: String = "") =
  command match {
    case "add" => s"Added ${id}: ${value}"
    case "remove" => s"Added ${id}"
    case "update" => s"Added ${id}: ${value}"
    case _ => s"Illegal command: ${command}"
  }

val added = execute("add", 42, "foo")
// added: String = Added 42: foo

val updated = execute("update", 42, "bar")
// updated: String = Added 42: bar

val removed = execute("remove", 42)
// removed: String = Added 42

val wowbanged = execute("wowbang", 73)
// wowbanged: String = Illegal command: wowbang

Perhaps you want to allow some flexibility in your command names. For example, another name for “add” could be “create.” Pattern matching expressions allow you to stack multiple conditions for which you want to take the same action using a pipe (|):

def execute2(command: String, id: Int, value: String = "") =
  command match {
    case "add" | "create" => s"Added ${id}: ${value}"
    case "remove" | "delete" => s"Added ${id}"
    case "update" | "change" => s"Added ${id}: ${value}"
    case _ => s"Illegal command: ${command}"
  }

val created = execute2("create", 84, "baz")
// created: String = Added 84: baz

Here Are Your Options

Perhaps you have a user variable that is an Option[String]. If the user is logged in, user is a Some; otherwise the user is an unauthenticated guest. You’d like to generate a greeting based on whether the user is logged in or not:

def greet(user: Option[String]) = user match {
  case Some(name) => s"Welcome back, ${name}!"
  case None => "Hello, dear guest! Please sign in!"
}

val personal = greet(Some("bcollins"))
// personal: String = Welcome back, bcollins!

val generic = greet(None)
// generic: String = 
//   Hello, dear guest! Please sign in!

Notice how the match expression can, in the case of the Some, unpack the value for you and assign it to a variable, name in this case. You don’t have to do it yourself.

Now given that Option is a binary choice, you may be tempted to think that an if-else block is probably a better, um, option. In some simple cases it may be, but in this case, you want to generate a message that differs by more than just the username. Look at what it takes to get the same results with an if-else block as the match expression above:

def greet2(user: Option[String]) =
  if (user.isDefined) {
    val name = user.get
    s"Welcome back, ${name}!"
  } else {
    "Hello, dear guest! Please sign in!"
  }

Now that’s not too bad, but compare that to the original version that uses the match expression. The match expression is just cleaner: It is very easy to see what the conditions are, and you don’t have to clutter the code by unpacking the Some value yourself.

Bearing with the Tuples of the Week

Pattern matching expressions can unpack tuples so that you can match on all values or individual values:

def getProducer(chars: (String, String)) =
  chars match {
    case ("Tom", "Jerry") => "Hanna-Barbera"
    case ("Bugs", "Daffy") => "Warner Brothers"
    case ("Mickey", _) => "Disney"
    case (x, "Buzz") => s"Pixar with ${x} and Buzz"
    case _ => "other"
  }

val prod = getProducer("Tom", "Jerry")
// prod: String = Hanna-Barbera

val prod2 = getProducer("Mickey", "Minnie")
// prod2: String = Disney

val prod3 = getProducer("Mickey", "Donald")
// prod3: String = Disney

val prod4 = getProducer("Woody", "Buzz")
// prod4: String = Pixar with Woody and Buzz

val prod5 = getProducer("Andy", "Buzz")
// prod5: String = Pixar with Andy and Buzz

val prod6 = getProducer("Ren", "Stimpy")
// prod6: String = other

As you can see in the “Disney” line, you don’t care what the second element of the tuple is, so you throw it away with the wildcard pattern. On the other hand, on the “Pixar …” line, you want to capture the first element in the matched tuple and use it in the result. So you just give it a variable name, and the compiler assigns the value to the variable for you, just like with Some(name) above.

What’s Your Type?

Finally, pattern matching expressions can match even on different types and take action based on the type of the input:

def report(guests: Any) = guests match {
  case guest: String =>
    s"Our guest: ${guest}"
  case all: Array[String] =>
    s"Our guests: ${all.mkString(", ")}"
  case count: Int =>
    s"We have ${count} guests"
  case _ => "Huh?"
}

val one = report("Brad")
// one: String = Our guest: Brad

val many = report(Array("Me", "Myself", "I"))
// many: String = Our guests: Me, Myself, I

val count = report(13)
// count: String = We have 13 guests

val stumped = report(3.14)
// stumped: String = Huh?

As you can see, you can choose from any number of types to match on and take action accordingly.

Categories
Tech

F# Friday – Pattern Matching, Part 1

A terribly useful technique in functional programming is pattern matching. Pattern matching is simply a form of conditional logic, like an if-else expression or (in other languages) a switch statement, but quite a bit more powerful and flexible. With pattern matching, you can perform matches and take action based on simple values, such as integers, but also on complex types and the values of their members. Here are some examples using the simpler types, and a future post(s) will illustrate how to match on more complex types.

On the Whole (Numbers)

Pattern matching on integers is very straightforward. Just use literals:

let getResponse talents =
    match talents with
    | 5 -> "Here are your five talents plus five more"
    | 2 -> "Here are your two talents plus two more"
    | 1 -> "Here is your one talent, which I hid"
    | _ -> "Uh, wrong story"

let response = getResponse 5
// val response : string = 
//   "Here are your five talents plus five more"

let apocryphal = getResponse 42
// val apocryphal : string = "Uh, wrong story"

Of course, the set of all possible integers is very large. Our example here only covers three specific values: 1, 2, and 5. To cover every other case that you don’t specify explicitly, use the wildcard pattern _, the underscore. That’s how we could handle 42. Or 103. Or −7. Or any other integer.

Getting to the (Floating) Point

Floating point numbers are difficult to pin down because of the margin of error, so you don’t typically match on a specific number. Usually you match on ranges. Pattern matching allows for that, too:

let getState temp =
    match temp with
    | x when x <= 32.0 -> "solid"
    | x when x >= 212.0 -> "gas"
    | _ -> "liquid"

let atRoomTemp = getState 70.0
// val atRoomTemp : string = "liquid"

let atSouthPole = getState -70.6
// val atSouthPole : string = "solid"

Putting a condition on a match with the when keyword like that is called a guard. Guards are simply Boolean expressions. You could alternatively write the “liquid” step in getState with a compound Boolean expression:

let getState2 temp =
    match temp with
    | x when 32.0 > x && x < 212.0 -> "liquid"
    | x when x >= 212.0 -> "gas"
    | _ -> "solid"
let onHotSummerDay = getState2 98.5
// val onHotSummerDay : string = "liquid"

In one more rewrite of getState, note that it is possible to use variables, not just literals, in guards:

let getState3 temp =
    let freezingPoint = 32.0
    let boilingPoint = 212.0
    match temp with
    | x when x <= freezingPoint -> "solid"
    | x when x >= boilingPoint -> "gas"
    | _ -> "liquid"
let inDeathValley = getState3 134.0
// val inDeathValley : string = "liquid"

Stringly Typed Interfaces

Perhaps your application executes commands, and those commands are specified by names, that is, strings. (Some folks jokingly call them “stringly typed interfaces.”) Pattern matching is perfect for this task:

let execute command id value =
    let v = defaultArg value ""
    match command with
    | "add" -> sprintf "Added %d: %s" id v
    | "remove" -> sprintf "Removed %d" id
    | "update" -> sprintf "Updated %d: %s" id v
    | _ -> sprintf "Illegal command: %s" command

let added = execute "add" 42 (Some "foo")
// val added : string = "Added 42: foo"

let removed = execute "remove" 42 None
// val removed : string = "Removed 42"

let updated = execute "update" 42 (Some "bar")
// val updated : string = "Updated 42: bar"

let wowbanged = execute "wowbang" 73 None
// val wowbanged : string = "Illegal command: wowbang"

Perhaps you want to allow some flexibility in your command names. For example, another name for “add” could be “create.” Pattern matching expressions allow you to stack multiple conditions for which you want to take the same action:

let execute2 command id value =
    let v = defaultArg value ""
    match command with
    | "create"
    | "add" -> sprintf "Added %d: %s" id v
    | "delete"
    | "remove" -> sprintf "Added %d" id
    | "change"
    | "update" -> sprintf "Added %d: %s" id v
    | _ -> sprintf "Illegal command: %s" command
let created = execute2 "create" 84 (Some "baz")
// val created : string = "Added 84: baz"

Here Are Your Options

Perhaps you have a user variable that is a string option. If the user is logged in, user is a Some; otherwise the user is an unauthenticated guest. You’d like to generate a greeting based on whether the user is logged in or not:

let greet user =
    match user with
    | Some name -> sprintf "Welcome back, %s!" name
    | None -> "Hello, dear guest! Please sign in!"

let personal = greet (Some "bcollins")
// val personal : string = "Welcome back, bcollins!"

let generic = greet None
// val generic : string = 
//   "Hello, dear guest! Please sign in!"

Notice how the match expression can, in the case of the Some, unpack the value for you and assign it to a variable, name in this case. You don’t have to do it yourself.

Now given that Option is a binary choice, you may be tempted to think that an if-else block is probably a better, um, option. In some simple cases it may be, but in this case, you want to generate a message that differs by more than just the username. Look at what it takes to get the same results with an if-else block as the match expression above:

let greet2 user =
    if Option.isSome user then
        let name = Option.get user
        sprintf "Welcome back, %s!" name
    else
        "Hello, dear guest! Please sign in!"

Now that’s not too bad, but compare that to the original version that uses the match expression. The match expression is just cleaner: It is very easy to see what the conditions are, and you don’t have to clutter the code by unpacking the Some value yourself.

Bearing with the Tuples of the Week

Pattern matching expressions can unpack tuples so that you can match on all values or individual values:

let getProducer chars =
    match chars with
    | ("Tom", "Jerry") -> "Hanna-Barbera"
    | ("Bugs", "Daffy") -> "Warner Brothers"
    | ("Mickey", _) -> "Disney"
    | (x, "Buzz") -> sprintf "Pixar with %s and Buzz" x
    | _ -> "other"

let prod = getProducer ("Tom", "Jerry")
// val prod : string = "Hanna-Barbera"

let prod2 = getProducer ("Mickey", "Minnie")
// val prod2 : string = "Disney"

let prod3 = getProducer ("Mickey", "Donald")
// val prod3 : string = "Disney"

let prod4 = getProducer ("Woody", "Buzz")
// val prod4 : string = "Pixar with Woody and Buzz"

let prod5 = getProducer ("Andy", "Buzz")
// val prod5 : string = "Pixar with Andy and Buzz"

let prod6 = getProducer ("Ren", "Stimpy")
// val prod6 : string = "other"

As you can see in the “Disney” line, you don’t care what the second element of the tuple is, so you throw it away with the wildcard pattern. On the other hand, on the “Pixar …” line, you want to capture the first element in the matched tuple and use it in the result. So you just give it a variable name, and the compiler assigns the value to the variable for you, just like with Some name above.

What’s Your Type?

Finally, pattern matching expressions can match even on different types and take action based on the type of the input:

let report (guests : obj) =
    match guests with
    | :? string as guest -> 
        sprintf "Our guest: %s" guest
    | :? (string array) as all -> 
        (all |> String.concat ", ")
        |> sprintf "Our guests: %s"
    | :? int as count -> 
        sprintf "We have %d guests" count
    | _ -> "Huh?"

let one = report "Brad"
// val one : string = "Our guest: Brad"

let many = report [|"Me"; "Myself"; "I"|]
// val many : string = "Our guests: Me, Myself, I"

let count = report 13
// val count : string = "We have 13 guests"

let stumped = report 3.14
// val stumped : string = "Huh?"

As you can see, you can choose from any number of types to match on and take action accordingly. Note that if the input argument does not contain a type annotation, such as (guests : obj) above, the compiler refuses to compile.

Categories
Tech

Scala Saturday – The Set.diff Method

Sometimes you have two sets of information, and you want to know what is in one set that the other set lacks. You want to perform a set difference operation.

What’s the Difference?

Given two sets, A and B, the difference between A and B—the items in A that are not in B—is written as follows:

A \ B

Likewise, the difference in B and A—the items in B that are not in A—is written vice versa:

B \ A

Set operations are frequently easiest to convey with a diagram:

An illustration of two sets, A and B, represented as two filled circles that are slightly overlapping. The difference (A \ B) is the part of set A not overlapping set B. The difference (B \ A) is the part of set B not overlapping set A.
The Difference in Two Sets A and B

It’s worth noting that a set difference operation is like arithmetic subtraction in that it matters which operand comes first. That is …

A \ B ≠ B \ A

White & nerdy mathematicians say that the set difference operation does not commute.

Always Never the Same

Continuing with my penchant for using band lineups as examples, put the original lineup of the band Kansas in one set and the current lineup in another:

val original = Set(
  "Walsh", "Livgren", "Williams",
  "Steinhardt", "Hope", "Ehart")
val current = Set(
  "Platt", "Manion", "Williams",
  "Ragsdale", "Greer", "Ehart")

To get the original members no longer with the band, use the Set.diff method to take the difference in the original lineup and the current:

val departed = original.diff(current)
// departed: scala.collection.immutable.Set[String] = 
//   Set(Walsh, Steinhardt, Livgren, Hope)

To get the current members who were not in the original lineup, do the opposite—take the difference in the current lineup and the original:

val noobs = current.diff(original)
// noobs: scala.collection.immutable.Set[String] = 
//   Set(Platt, Ragsdale, Manion, Greer)

How ’bout that! Simple enough, I suppose, but seeing as set difference is a whole lot like arithmetic subtraction, wouldn’t it be really nice if we could express our set difference operations just like we do arithmetic subtraction?

A − B

Good news: You can! Well, almost. Scala defines a -- operator so that we can more mathematical-looking code:

val departed = original -- current
val noobs = current -- original
// departed: scala.collection.immutable.Set[String] = 
//   Set(Walsh, Steinhardt, Livgren, Hope)
// noobs: scala.collection.immutable.Set[String] = 
//   Set(Platt, Ragsdale, Manion, Greer)

Incidentally, Scala does also define a minus operator, but it is for removing one item at a time, not a set of items. However, with it you can write code like this:

val noRhythm = current - "Ehart" - "Greer"
// noRhythm: scala.collection.immutable.Set[String] = 
//   Set(Platt, Ragsdale, Manion, Williams)
Categories
Tech

F# Friday – The Set.difference Function

Sometimes you have two sets of information, and you want to know what is in one set that the other set lacks. You want to perform a set difference operation.

What’s the Difference?

Given two sets, A and B, the difference between A and B—the items in A that are not in B—is written as follows:

A \ B

Likewise, the difference in B and A—the items in B that are not in A—is written vice versa:

B \ A

Set operations are frequently easiest to convey with a diagram:

An illustration of two sets, A and B, represented as two filled circles that are slightly overlapping. The difference (A \ B) is the part of set A not overlapping set B. The difference (B \ A) is the part of set B not overlapping set A.
The Difference in Two Sets A and B

It’s worth noting that a set difference operation is like arithmetic subtraction in that it matters which operand comes first. That is …

A \ B ≠ B \ A

White & nerdy mathematicians say that the set difference operation does not commute.

Always Never the Same

Continuing with my penchant for using band lineups as examples, put the original lineup of the band Kansas in one set and the current lineup in another:

let original =
    set ["Walsh"; "Livgren"; "Williams";
         "Steinhardt"; "Hope"; "Ehart"]
let current = 
    set ["Platt"; "Manion"; "Williams";
         "Ragsdale"; "Greer"; "Ehart"]

To get the original members no longer with the band, use the Set.difference function to take the difference in the original lineup and the current:

let departed = Set.difference original current
// val departed : Set<string> =
//   set ["Hope"; "Livgren"; "Steinhardt"; "Walsh"]

To get the current members who were not in the original lineup, do the opposite—take the difference in the current lineup and the original:

let noobs = Set.difference current original
// val noobs : Set<string> = 
//   set ["Greer"; "Manion"; "Platt"; "Ragsdale"]

How ’bout that! Simple enough, I suppose, but seeing as set difference is a whole lot like arithmetic subtraction, wouldn’t it be really nice if we could express our set difference operations just like we do arithmetic subtraction?

A − B

Good news: You can! F# defines a minus operator so that we can do exactly that:

let departed = original - current
let noobs = current - original
// val departed : Set<string> = 
//   set ["Hope"; "Livgren"; "Steinhardt"; "Walsh"]
// val noobs : Set<string> = 
//   set ["Greer"; "Manion"; "Platt"; "Ragsdale"]
Categories
Tech

Scala Saturday – The Option Type, Part 3

One more word on the Option type. While Option allows you a more type-safe alternative to nulls, it does not itself handle nulls. In other words, this …

val s = Some(null)

… gets you a Some containing a null. That doesn’t help so much if our aim is to get away from null, not kick it down the road.

The Java Way

In version 8, Java introduced its own Optional type, no doubt inspired by the Option and Maybe types available in the functional languages. It does handle nulls. Take the following classes as examples:

public class User {
  private String username;
  private String name;
  
  public User(String username) { this(username, null); }
  public User(String username, String name) {
    this.username = username;
    this.name = name;
  }
  
  public String getUsername() { return username; }
  public String getName() { return name; }
}

public class Session {
  private User user;
  
  public Session() { this(null); }
  public Session(User u) { this.user = u; }
  
  public User getUser() { return user; }
}

public class Application {
  private Session session;

  public Application() { this(null); }
  public Application(Session s) { this.session = s; }
  
  public Session getSession() { return session; }
}

Because Optional handles null in its map operation, this works:

Application app = new Application(new Session());
String name = Optional.of(app)
                .map(Application::getSession)
                .map(Session::getUser)
                .map(User::getName)
                .orElse("n/a");
// name = "n/a"

In our example, the Session has a null User property. But that’s OK, because the map operation on line 4 (highlighted above) takes that null and converts it to a None, or more accurately, an Empty per Java parlance.

Back in Scala Land

We cannot do quite the same thing in Scala. Now we, as enlightened Scala developers, would never code up something that uses nulls all over the place like the Java classes above. But the Java world is more comfortable with nulls, so let’s say that you are working with a library that contains those Java classes. You pull the JAR into your Scala project and write something like this:

val app = new Application(new Session())
val name = Option(app)
             .map(_.getSession)
             .map(_.getUser)
             .map(_.getName)
             .getOrElse("n/a")
// NullPointerException!!!

But that breaks down pretty quickly. Line 4 (highlighted above) yields an exception because _.getUser is null. Option.map in Scala does not convert a null to a None. So then, what do we do?

Well, you can instantiate an Option by applying the Option object. Option() does take an object reference and return a None if it is a null, or a Some if it is not. Also, remember that Option.flatMap takes an operation that returns an Option and flattens it so that it does not return a nested Option, but just an Option. Therefore, you can change your code to this:

let app = Application(Session())
val name = Option(app)
             .flatMap(a => Option(a.getSession))
             .flatMap(s => Option(s.getUser))
             .flatMap(u => Option(u.getName))
             .getOrElse("n/a")
// name : String = "n/a"

It’s a bit more headache than you’d like, but that’s what you get for using flaky Java code, right?

Categories
Tech

F# Friday – The Option Type, Part 3

One more word on the Option type. While Option allows you a more type-safe alternative to nulls, it does not itself handle nulls. In other words, this …

let s = Some null

… gets you a Some containing a null. That doesn’t help so much if our aim is to get away from null, not kick it down the road.

The Java Way

In version 8, Java introduced its own Optional type, no doubt inspired by the Option and Maybe types available in the functional languages. It does handle nulls. Take the following classes as examples:

public class User {
  private String username;
  private String name;
  
  public User(String username) { this(username, null); }
  public User(String username, String name) {
    this.username = username;
    this.name = name;
  }
  
  public String getUsername() { return username; }
  public String getName() { return name; }
}

public class Session {
  private User user;
  
  public Session() { this(null); }
  public Session(User u) { this.user = u; }
  
  public User getUser() { return user; }
}

public class Application {
  private Session session;

  public Application() { this(null); }
  public Application(Session s) { this.session = s; }
  
  public Session getSession() { return session; }
}

Because Optional handles null in its map operation, this works:

Application app = new Application(new Session());
String name = Optional.of(app)
                .map(Application::getSession)
                .map(Session::getUser)
                .map(User::getName)
                .orElse("n/a");
// name = "n/a"

In our example, the Session has a null User property. But that’s OK, because the map operation on line 4 (highlighted above) takes that null and converts it to a None, or more accurately, an Empty per Java parlance.

Back in .NET Land

We cannot do quite the same thing in F#. Now we, as enlightened F# developers, would never code up something that uses nulls all over the place like the Java classes above. But the C# world is more comfortable with nulls, so let’s say that you are working with a C# library that contains the analogs to the Java classes above:

public class User
{
    public string Username { get; private set; }
    public string Name { get; private set; }

    public User(string username, string name = null)
    {
        Username = username;
        Name = name;
    }
}

public class Session
{
    public User User { get; private set; }

    public Session(User u = null) { User = u; }
}

public class Application
{
    public Session Session { get; private set; }

    public Application(Session s = null) { Session = s; }
}

You pull that library into your F# project and write something like this:

let app = Application(Session())
let name =
    Some app
    |> Option.map (fun a -> a.Session)
    |> Option.map (fun s -> s.User)
    |> Option.map (fun u -> u.Name)
    |> defaultArg <| "n/a"
// NullReferenceException!!!

But that breaks down pretty quickly. Line 5 (highlighted above) yields an exception because s.User is null. Option.map in F# does not convert a null to a None. So then, what do we do?

Well, if you’re using F# 4.0, there is something new to the Option module: Option.ofObj. It is essentially a named constructor for Option. It takes an object reference and returns a None if it is a null, or a Some if it is not. Also, remember that Option.bind takes an operation that returns an Option and flattens it so that it does not return a nested Option, but just an Option. Therefore, you can change your code to this:

let app = Application(Session())
let name = 
    Some app
    |> Option.bind (fun a -> Option.ofObj a.Session)
    |> Option.bind (fun s -> Option.ofObj s.User)
    |> Option.bind (fun u -> Option.ofObj u.Name)
    |> defaultArg <| "n/a"
// name : string = "n/a"

It’s a bit more headache than you’d like, but that’s what you get for using flaky C# code, right?

If you’re not using F# 4.0 yet, then you can write a little utility function to do the same job:

let nullToOption = function 
                   | null -> None
                   | x -> Some x

let app = Application(Session())
let name = 
    Some app
    |> Option.bind (fun a -> nullToOption a.Session)
    |> Option.bind (fun s -> nullToOption s.User)
    |> Option.bind (fun u -> nullToOption u.Name)
    |> defaultArg <| "n/a"
// name : string = "n/a"
Categories
General

Disapproval vs. Hate

Do not mistake disapproval for hate.

Categories
Tech

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