Thursday, April 30, 2009

Combinators for Pretty Printers, Part 1

Scala has a flexible and powerful syntax that is very convenient when building libraries. Among the best examples of Scala's syntactic power put to excellent use are the parser combinator libraries in the standard distribution. Code that uses Scala's parser combinators looks remarkably like BNF (the standard notation for describing formal language grammars) but is actually an executable program which parses the language it describes.

Consider the BNF for a simple expression grammar:

expr     ::= sum
sum ::= product { ("+" | "-") product }
product ::= power { ("*" | "/") power }
power ::= factor [ "^" factor ]
factor ::= "(" expr ")" | variable | constant
variable ::= identifier
constant ::= floatLiteral
And the equivalent Scala code using parser combinators:
def expr     = sum
def sum = product ~ rep(("+" | "-") ~ product)
def product = power ~ rep(("*" | "/") ~ power)
def power = factor ~ opt("^" ~ factor)
def factor = "(" ~ expr ~ ")" | variable | constant
def variable = ident
def constant = floatLit
If you want to learn more about Scala's parser combinators, there are several good articles on them by Debasish Ghosh, Daniel Spiewak, Jim McBeath, and Ted Neward.

What I want to write about today are pretty printer combinators. If a parser takes a stream of characters and turns them into an abstract syntax tree, a pretty printer does the opposite: it turns some tree into a string, subject to some constraints (to keep the output "pretty"). I've found myself needing to programmatically generate Scala code, but I want the output to be human-readable as well as valid Scala syntax. There is no equivalent to BNF for pretty printers, but my goal is to create a library of combinators to encode pretty printing rules in a custom syntax.

A Pretty Printer Algebra

Lets put aside concerns about syntax for now and think about the underlying mechanics of pretty printers. Phil Wadler, the same person who popularized parser combinators, describes an algebra for pretty printers in his paper "A prettier printer". Without getting into the details of why this is an "algebra", let's take a look at how Wadler's insights might be encoded in Scala.
sealed abstract class Doc
case object Empty extends Doc
case object Line extends Doc
case class Text (s: String) extends Doc
case class Cons (left: Doc, right: Doc) extends Doc
This code describes four kinds of documents. The Empty document is self-explanatory. The Line document represents a new line. The Text document represents raw text (which MAY NOT contain new lines). The Cons document joins together two other documents. Given these rules, it's trivial to define a layout method that turns a Doc into a String.
def layout(d: Doc): String = d match {
case Empty => ""
case Line => "\n"
case Text(s) => s
case Cons(l, r) => layout(l) + layout(r)
}
Let's see how we might use this to encode a document that contains a block of Scala syntax:
val doc =
Cons(Text("def theAnswer {"), Cons(Line,
Cons(Text(" var i = 42"), Cons(Line,
Cons(Text(" println(i)"), Cons(Line,
Text("}")))))))

layout(doc)
// returns:
// "def theAnswer {
// var i = 42
// println(i)
// }"
These building block are sufficient to encode any document with any layout. The only problem is, well, they're not very useful. For example, we had to manually specify the indentation level of the code inside the brackets for each line independently. Keeping track of details like this is tedious, error-prone, and mechanical; it's just the kind of thing we should let computers do for us. With this use-case in mind, let's add a new kind of document:
case class  Nest  (n: Int, d: Doc)        extends Doc
The Nest document is actually a transformation on an existing document. It modifies the preexisting document by adding n spaces after every line found in the enclosed document. We can encode the same document we did before, with the same final layout, without manually adding spaces but instead using our new Nest document:
val doc =
Cons(Text("def theAnswer {"), Cons(Nest(2, Cons(Line,
Cons(Text("var i = 42"), Cons(Line,
Text("println(i)"))))), Cons(Line,
Text("}"))))

layout(doc)
// returns: same as above
This also means our layout method needs to take into account the new Nest document.
def layout(d: Doc): String = d match {
... as above ...
case Nest(n, Empty) => layout(Empty)
case Nest(n, Line) => "\n" + (" " * n)
case Nest(n, Text(s)) => layout(Text(s))
case Nest(n, Cons(l, r)) => layout(Cons(Nest(n, l), Nest(n, r)))
case Nest(i, Nest(j, x)) => layout(Nest(i+j, x))
}
The second case gives the key function of nesting: it adds n spaces after every newline. The rest of the cases state that nesting does nothing to Text and Empty, that it applies to both documents inside a Cons, and that nested Nests just add together.

There's still the issue of syntax. We'd like something a little prettier than the mess of nested parentheses we have now. Let's add an implicit, a few shortcuts, and a convenient definition for block which puts stuff in braces and automatically idents it.
sealed abstract class Doc {
def ~(that: Doc) = Cons(this, that)
def ~~(that: Doc) = this ~ space ~ that
def <~(that: Doc) = this ~ line ~ that
def ~>(that: Doc) = this ~ nest(2, line ~ that)
}

implicit def string(s: String): Doc = Text(s)
val line = Line
val space = Text(" ")
def nest(n: Int, d: Doc) = Nest(n, d)
def block(d: Doc): Doc = space ~ "{" ~> d <~ "}"
This lets us define our simple document like so:
val doc =
"def theAnswer" ~ block(
"var i = 42" <~
"println(i)"
)

layout(doc)
// returns:
// "def theAnswer {
// var i = 42
// println(i)
// }"
Much better!

We've assembled enough functionality to have a rudimentary pretty printer combinator. With this we can build pretty printers from very simple combinators. There's still a lot of work to be done: higher-level combinators, columns and alignment, and the ability to describe groups of layouts and to choose among them the one that best fits the width of the page. We'll go through all this and more in Part 2 of Combinators for Pretty Printers.

Monday, April 27, 2009

OSGi matters! - Scala libraries as OSGi bundles

No question: Scala is great! At least that’s what every Java developer would think. But just like Java Scala is lacking a higher-level module system. As there is currently no support for modularity built into the JVM, it is up to a framework to provide such. There is a well established and mature module framework around: OSGi. It lets us define modules called bundles which are just usual JARs with some additional metadata. But what are the benefits of going for OSGi bundles instead of plain JARs?
First, a bundle declares its public API and its dependencies. Hence we can really hide our implementations which gives us a great deal of flexibility.
Second, bundles, exported packages (public API) and imported packages (dependencies) use version numbers. This allows for installing the same bundle in different versions at the same time. No more JAR hell!
Third, OSGi is a dynamic module system: Bundles can be installed, updated and uninstalled anytime. This enables real hot deployment.
There are a lot of further benefits, e.g. a service-oriented architecture which enables loose coupling, different standard services for common tasks like logging, http, etc., but it should already be obvious, that OSGi makes a lot of sense.
As OSGi purely relies on Java, it is easy and straightforward to enable OSGi for Scala: Just provide the Scala libraries (scala-lang.jar, scala-swing.jar, etc.) as OSGi bundles with suitable bundle manifests. The “official” Scala libraries are not (yet) delivered as OSGi bundles. There is an Eclipse plug-in which is part of the Scala IDE for Eclipse which basically is an OSGi bundle, but it is an all-in-one bundle (assembles scala-*.jar) and - very important - contains a rather special bundle manifest that is not-so-good for general purpose.
Therefore I have created the scala-lang-osgi project which provides OSGi bundles for each Scala library. No changes are made to the libraries themselves but only the necessary manifest headers are added to the MANIFEST.MF file. All OSGi-fied Scala libraries are deployed to the scala-tools.org Maven repository with group id org.scala-lang-osgi using the same artifact id and version as the non-OSGi Scala libraries (e.g. scala-library, scala-swing, etc.). Of course there is also a snapshot repository.
These OSGi-fied Scala libraries are already used in projects that rely on OSGi and Scala, e.g. ScalaModules and BindForge. They will also be used for OSGi-fying Lift. If you also go for OSGi on Scala, please give it a try and give me your feedback.

Sunday, April 26, 2009

ANN: Brisbane Scala Group has formed

I am pleased to announce that the Brisbane Scala Group has recently formed. This group is dedicated to exploring both Scala and the wider functional program ecosystem in which it sits.

If you are a Scala enthusiast in Brisbane (Australia), or are interested in learning more about Scala or general functional programming, head over to the Brisbane Scala Group.

Wednesday, April 22, 2009

ANN: Melbourne Scala User Group's First Meeting - Next Monday, April 27th

The Melbourne Scala User Group is having its first meeting next Monday, April 27th at 6:30pm. Full details of the meeting are just a click away.

Topics covered will include

  • Scala's Object Model
  • Traits
  • Combining Object-Oriented and Functional programming
    presented by Ben Hutchison

  • Scala's XML Support
    presented by Mark Ryall

  • Specs BDD Framework
    presented by myself
As a bonus, David Pollak and Apress have been generous enough to provide a good quantity of eBook coupons for the use of attendees to purchase Beginning Scala and Exploring Lift at a discount. These will be made available to anyone interested on the night.

I look forward to seeing some of you there.

Sunday, April 19, 2009

Lift's view code binding system

If you're a Lift user, you might like this blog entry I wrote which explains Lift's view code binding system. It explains how Lift's "bind" method works with XHTML templates and Mapper classes to render XHTML to the browser. It's one of the most-used methods in Lift, so it's worth checking out:


Read the full article here

Saturday, April 18, 2009

Ann: New York Scala Enthusiasts: Testing in Scala, April 27th at 6:30pm

Hey,

Thanks everyone for coming last Thursday, we had a great "emergency" with Jorge Ortiz, and on that note we're going to keep it going with Josh Cough on April 27th - here are the details:

http://www.meetup.com/New-York-Scala-Enthusiasts/
Josh Cough of both planetscala and ScalaTest fame - and probably one of the groups most experienced Scala developers - will be discussing "Testing with Scala" at our next meetup, April 27th at 6:30pm.

Josh is working with Bill Venners to develop ScalaTest, a testing framework designed to facilitate different styles of testing, including some interesting behavior driven testing and more traditional JUnit/TestNG style testing. However, Josh wanted to emphasize his discussion will cover the many methods available for testing in Scala, not just ScalaTest. Quoting Josh directly:

"I noticed that a lot of the people at the meetup were newcomers, both to our meetup and to Scala. To accommodate the them, the talk will be more of a gentle introduction than this past meetup (which wasn't an introduction at all). I think this approach meshes well with ScalaTest, which eases you into Scala by supporting many of the ways that Java developers are used to programming tests, including JUnit and TestNG. After the introduction we'll be cover more advanced features in ScalaTest, move onto Specs, mocking in Scala, and ScalaCheck, time permitting. The talk should have plenty enough content and gusto to captivate the more experienced Scala developers in the group. I'm really excited."

Josh has shown great insight and experience with Scala at all of our meetings, and this should be a great presentation. Check out his blog http://jackcoughonsoftware.blogspot.com/ and get ready for a great meeting!

Thursday, April 9, 2009

Ann: New York Scala Enthusiasts: Jorge Ortiz shares his Scala Tips

April 16th at 6:30pm. I know it's short notice, but as n8than says, "little bird told us that Jorge Ortiz is in town so we're tying him down for an impromptu meetup. Ortiz is an early Scala user and Lift web framework committer who taught a Scala class at Stanford last year (CS94SI: Cross-Paradigm Programming with Scala). You may know him from his posts at scala-blogs.org and his frequent, insightful help on the Scala mailing list."

This one should be awesome, and I hope everyone can make it! Here is the link to the meetup.