asoft
sea

~ tiny vessels of code slowly floating out to sea

Powered by a motorboat called the S.S.Tumblr

3 years ago

@9:37pm

Comments

magic match sticks and burnt fingers

First class pattern matching support is one of the many ways Scala stole my heart. I now use pattern matching as a superior refactoring and design tool in place of most every use case where I would historically insert another stray branch into a nest of ifs or query methods. Scala’s match keyword does what most languages switch or case keywords should do. Some may argue there’s too much magic behind it but once you understand that happens behind the curtains with unapply, most of that unfounded distrust goes away. For me, it’s just just the right amount of magic for me enjoy sticking my hand in the magician’s hat without the fear of uncertainty.

That doesn’t ways mean what my hand draws from the magicians hat is always what I expect.

Let’s look an extremely contrived example of using pattern matching.

def isRabbit(contents: String) =
  contents match {
    case "Buggs" => true
    case "Roger" => true
    case "Jessica" => false
    case _ => false 
 }

I’ve seen this trick enough to know that when I put my hand in, I have a pretty good idea of what I’ll get out depending on it’s contents. When see the magician stuff Buggs bunny into his hat before the show, I know I will pull out a rabbit. When I see the magician stuff Jessica Rabbit into his hat before the show, I know I will not being pulling out a rabbit. We’ve all been to that show before.

Now. We are good at extracting the hardcoded string values of our applications are’t we? Let’s extract thems that be causin all the code smell.

val buggs = "Buggs"
val roger = "Roger"
val jess = "Jessica"

def isRabbit(contents: String) =
  contents match {
    case buggs => true
    case roger => true
    case jess => false
    case _ => false 
 }

Can you guess what the contents of the hat will reveal when the magician puts “Roger” into the hat before the show? You sure? Okay. Now paste the code above into your nearest scala repl.

Ouch! Looks like you just got burnt. What’s with all this error: unreachable code business? Scala is supposed to prevent me from having buggs in my program, isn’t it?

Unbeknownst to me until recently is a little bit of knowledge that I hope to bestow upon the likes of you. So quiet the television and come sit close to the fire. Scala’s pattern matching engine will not treat lowercase variable names the same as will their value in match clauses. Don’t assume you can just use variables in the values’ stead without getting burnt. But, there is hope for sorry souls.

Scala has a convention for naming contants and so does English for its proper nouns: the first letter should be upper-cased.

Let’s revisit this ridiculous example so I can get to the point. Let’s rename those proper nouns using upper case identifiers.

val Buggs = "Buggs"
val Roger = "Roger"
val Jess = "Jessica"

def isRabbit(contents: String) =
  contents match {
    case Buggs => true
    case Roger => true
    case Jess => false
    case _ => false 
 }

Ah, ha! It totally works now. Why? Because scala treats pattern match case arguments that are identifiers as extractors and by convention an identifier starting with an uppercase letter is assumed to be a constant identifier. A constant can statically be compiled in bytecode because it will not change. A lowercase identifier by convention is not, and therefore is a lesser citizen and can be assumed to vary at runtime and cannot be statically compiled as a pattern match clause. So why do inline, hard coded strings work then? Duh. Strings are immutable and can not change so they can be statically compiled with the pattern match clause. With this information in hand, we should hopefully see why the semi-compiled version using lower case variable names errors out. The remaining case statements would never be reached and Scala thankfully lets us know this at compile time. One of the benefits you are afforded in a statically compiled language. At least this is my hypothesis :)

Before this magic show ends, I’d like to point out a lesser know feature of Scala’s syntax. Enter: the backtick! In some rare cases where you can just not stand to not use lower case variable names or when you get the itch to name something using a language keyword, you can wrap the identifier in a set of backticks. This will say to Scala: “Hey, I know this is wrong but give me a break. The magic business hasn’t been all that great lately”. Scala, being the nice language it is will reply: “Okay, I’ll let is one go for now”.

So if you absolutely wanted to use lower case identifiers in pattern match clauses, you can sneakily get away with the following.

def isRabbit(contents: String) =
  contents match {
    case `buggs` => true
    case `roger` => true
    case `jess` => false
    case _ => false 
 }

An surprisingly you can also get away with tomfoolery like this.

val `val` = "ue"
println(`val`)

the magician bows

I’d like to thank @boia01 and @jorgeortiz85 for some helpful insight on some frustration I had with an almost unrelated issue but with a totally related answer.

Enjoy the show!

  1. coderspiel reblogged this from asoftsea and added:
    Backticks!
  2. asoftsea posted this
blog comments powered by Disqus