Scala: Fancy Summation

 

I am currently looking at the Scala language, and the more I learn about it the more I like it. One part that got me really interested is the support for domain-specific languages in Scala.
 
When it comes to DSLs, there are generally two kinds: internal and external. In traditional languages, external DSLs are often the only realistic way. External simply means that you create your own parser and everything for the new language. Quite an effort, often a large tool-chain, and rather hard to maintain. Scala does have awesome parser combinators, which at least reduces the tool-chain significantly, as you can write your parser directly in Scala. With a little bit of care, you can even parse the full LL(*) segment.
 
A totally different approach are internal DSLs. Internal means that you rely solely on the capabilities of your chosen programming language and try to bend it to your will in some suitable way. In most languages this forces you to religiously adhere to the original language's syntactical restrictions for your DSL. Not so with Scala. I was interested in trying to create a simple DSL that allows you to sum objects merely by writing them after each other. No operators, just whitespace separators.
 
This little piece of Scala code already succeeded at this task:

case class C(x:Int) {
	var sum = x
	def C(x:Int) = {
		sum += x
		this
	}
}

With this you can now write code like the following:


scala> C(3)
res0: C = C(3)

scala> C(3) sum
res1: Int = 3

scala> C(3) C(4) C(5)
res2: C = C(3)

scala> C(3) C(4) C(5) sum
res3: Int = 12

No operators, just whitespace. Of course, summation is really just a demonstration of the concept. As you can see the C method returns the object itself, hence, we can chain together the objects and perform any arbitrary left-associative folding operation on these objects.

When you compare this with an external DSL it's quite impressive, especially considering the concise implementation. No lexer, no parser, just a method. However, as usual with internal DSLs one hits the boundaries eventually. For me, it is the question how to combine this behavior with differing case classes. The naming of the method is certainly no coincidence and indeed, if you try to extend this DSL via subclassing new case classes it fails:


class Base(x:Int) {
	var sum = x
	def C(x:Int) = {
		sum += x
		this
	}
}
case class C(x:Int) extends Base(x)
case class D(x:Int) extends Base(x)


scala> C(3) C(4) C(5) sum
res0: Int = 12

scala> C(3) D(4)
<console>:9: error: value D is not a member of C
       C(3) D(4)
        ^

I'm still new to these powerful internal DSLs (and of course Scala itself), so maybe I'm just missing something obvious. If you happen to have an idea how to achieve something like the above that allows for free mixing and statements like "C(3) D(4) E(5) C(6)", let me know in the comments.

Comments

That's funny, I came here from Anki (your IR plugin) and saw an article on Scala, which I am learning too.

I was thinking about making Anki cards on Scala, apparently nobody did that yet. Not sure yet which form they will take...

Cool. I'm unfortunately very short on time these days, but if you can manage to throw a decent deck together, I'd really appreciate it if you could send me a copy of it.