Header

Eliminating Pattern Matching

In the last few years, I worked on several Java projects where we transformed and analyzed abstract syntax trees, so when I started learning Scala, pattern-matching quickly became one of my favorite language features. I could never warm up to the visitor pattern, so I was thankful that Scala offered a much more powerful alternative.

What I also liked very much was Scala’s consistent use of the Option type in its standard library. Now, instead of having to read the documentation to find out whether some call could return null, the type checker forced me to handle this where necessary. So a lot of my early Scala code looked as follows:

doSomething() match {
  case Some(value) => Some(doSomethingElse(value))
  case None => None
}

While it’s still possible to get a NPE in Scala, it just doesn’t happen with well-written libraries, simply because there’s no need to ever use null.

(By the way, isn’t it funny that Java forces you to check exceptions but doesn’t help you with the much more common and annoying null problem?)

So yes, in practice, Options do save you from NPEs. Does your code also get smaller (because usually, in Scala it will)? Not if you pattern match on Some/None, all the un-wrapping and lifting is quite verbose.

Nowadays, certainly influenced by all the discussions on monads, I realize that pattern-matching on Option is a very primitive form of abstraction, and instead of the code above I now write:

doSomething() map (value => doSomethingElse(value))

(For those unfamiliar with functional programming, map applies the function to the value inside a Some, and does nothing when called on a None.)

Even better, we can fully automate this refactoring! I’m currently working on a first version in the scala-refactoring library. So far, I’ve implemented the refactoring for map, but there are many more we can do, for example:

  • If the Some case does not construct a Some but calls a function that returns an Option, we use flatMap instead of map.
  • If the Some case evaluates to Boolean and the None case returns false, we can replace it with exists. If Some returns true and None returns false, we can just replace the whole pattern match with isDefined.
  • When the None case is (), we can transform to foreach.

So far we have only looked at Option, but there is more: for example, we could also replace pattern-matching on lists and recursion with folds. I’m sure somebody has already written a paper about such refactorings, but I haven’t found anything yet.

What do you think about eliminating pattern matching? Do you also prefer mapping to explicit pattern-matching?

18 comments »
Header

Scala Refactoring Thesis Finished

I’m done! A few minutes ago, I handed in my thesis on Scala Refactoring.

The project also has a new home at scala-refactoring.org, where you can find more about the refactorings I implemented, how they can be used, etc. I also recommend reading my report, but if you just want an overview, take a look at the poster:

The next steps for me now are to go on holidays, so please excuse if I don’t respond for a week.

4 comments »
Header

DIY Refactoring for Scala

Excuse my long absence from blogging, but I have a good excuse: I’ve been hard at work on my Scala Refactoring project.

Today, I’m going to show you how you can implement your very own automated refactoring for Scala. “Implement a refactoring you say? But I don’t use IDE xy!”. Don’t worry, you won’t have to use a specific IDE, in fact, you don’t need to use an IDE at all.

Why should you want to write a refactoring? IDEs usually provide a bunch of general refactorings and code generators, but maybe you need a framework or project specific one that no IDE will implement for you. And don’t worry, it is not as complicated as it might sound. (And I should add that when I write refactoring, this includes all program transformations that affect the source code, so you could also create a transformation that just creates new code.)

A refactoring is essentially a transformation of the program in its tree form. Unfortunately, our programs are stored in plain text files, so the transformed tree has to be converted back to text, and this without losing all our pretty formatting. One of the design goals of the Scala Refactoring library was to separate these two concerns as good as possible, so that the implementor (you!) of a refactoring can concentrate on transforming trees and let the library do all the ugly code generation for him. To make it easier for those who already know the Scala compiler’s abstract syntax tree, the refactorings are completely based on this AST instead of introducing a new program representation. I can’t introduce Scala’s AST in detail here, but there’s an introduction in my term project’s technical report which I also plan to expand in my master’s thesis (please give me feedback if you notice any errors).

Please continue reading the rest of the post on my project wiki (where the layout is much more suited for source code).

4 comments »
« Older
Newer »