« Scala for C# programmers, part 5: implicits | Main | Mathematics and programming »
March 29, 2009
Scala for C# programmers, part 6: infix operators
C#, like most object-oriented programming languages, is pretty strict about how you call methods: you use the dot notation, unless the method is a special ‘operator’ method such as operator+, operator== or a conversion operator. The special operator methods are predefined by the compiler: you can write your own implementation, but you can’t create your own operator names. You can teach the + operator how to handle your custom type, but you can’t add an exponentiation operator:
int a = b ** c;
C# has three problems with this: first, it doesn’t like the method name “**”; second, it doesn’t like that there’s no . before the name; and third, it doesn’t like that there’s no brackets around the method argument.
To get around the objection to the name, let’s compromise and call it ToThe for now. So what C# insists on seeing is a.ToThe(b).
Scala, like many functional languages, isn’t so strict. Scala allows you to use any method with a single argument in an infix position. Before we can see this in the exponentiation example, we need to pimp the Double type with the toThe method:
import Implicits._
import System.Math._
class DoubleExtensions(d : Double) {
def toThe(exp: Double): Double = Pow(d, exp)
}
object Implicits {
implicit def DoubleExtensions(d : Double) = new DoubleExtensions(d)
}
Recall that this is just the Scala idiom for extension methods – it’s the equivalent of writing public static ToThe(this double first, double second) { … } in C#. (If we were wanting to use infix notation with our own class, we wouldn’t need all this malarkey.) So now we can write:
val raised = 2.0.toThe(7.0)
Okay, so what do we need to do to get this to work in infix position? Nothing, it turns out.
val raised = 2.0 toThe 8.0 // it just works
This still doesn’t look much like a built-in operator, but it turns out Scala is less fussy than C# about method names too.
class DoubleExtensions(d : Double) {
def **(exp: Double): Double = Pow(d, exp)
}
val raised = 2.0 ** 9.0 // it still just works
Much nicer.
This sorta-kinda works for postfix operators too:
class StringExtensions(s : String) {
def twice : String = s + s
}
val drivel = "bibble" twice;
The semicolon is required when you invoke a method using postfix notation, which is a bit warty, but life goes on.
Infix and postfix operator support is obviously fairly simple syntactic sugar over normal dot notation. But this seemingly minor feature is very important in constructing DSLs, allowing Scala to do in internal DSLs what many languages can do only using external tools. For example, where most languages do parsing via an external file format and a tool to translate that file format into native code (a la lex and yacc), Scala’s parser library makes extensive use of infix and postfix operators to provide a “traditional” syntax for describing a parser, but manages it entirely within the Scala language. I’ll take a closer look at this in a future post.
March 29, 2009 in Software | Permalink
TrackBack
TrackBack URL for this entry:
https://www.typepad.com/services/trackback/6a00d8341c5c9b53ef01156f7fc1e7970b
Listed below are links to weblogs that reference Scala for C# programmers, part 6: infix operators:
Comments
I've always wondered why C# doesn't allow infix operators since as you point out it is only syntactic sugar around already existing features...
Posted by: Duncan at Jul 9, 2009 10:02:13 AM