Scala has the reputation of being a complicated and bloated language. This impression comes from the large variety of libraries, architectures, and styles out there. Since developers have so many ways of using the language, the argument goes that the language is just an overly complicated mix of every programming languages features ever invented. This couldn’t possibly be further from the truth.

What is true is that Scala is complex. However this complexity is not coming from the language, it is just the inherent complexity in writing software. Complexity should also not be confused with complication. Saying that something is complicated carries a notion that the thing was made complicated for the sake of it. It could have been made simpler. Complexity is the nature of the thing, and it’s inherent to the depth of the problem.

Things can be basic or complex, but not both, and things can be simple or complicated, but not both. A basic problem should be ideally solved by a simple solution, however it is very common to introduce a complicated solution to a basic problem. A complex problem can rarely be solved by a simple tool, although when that happens, that’s usually the product of a genius. And some problems are just so complex that they require a complicated solution, but it’s never ideal. Scala is a tool which is not simple, but not complicated either, made to address a very complex domain.

But I disgress; the essence of the criticisms against Scala often boils down to its bloated amount of features. Scala does have quite a number of features, many of them coming from advanced research in programming languages, which makes it a hard and challenging language to learn. But hard and challenging does not mean in any way bad. VIM is maybe the best text editor ever invented (along with Emacs), but it is also one of the hardest to learn and to master. But the effort eventually pays off, for when one finally understands its design philosophy, they unlock an unbounded boost in productivity.

Scala has many features, but many of them are orthogonal to each other. What that means is that each feature brings a unique and necessary aspect to the language. Its design was actually carefully crafted so that only the minimal necessary set of features was added to the language. The expressiveness that people observe with Scala does not come from a large number of features, but from the powerful synergy among them. Each feature is individually clean and well-defined, and it can combine with every other features.

Let’s move this abstract discussion to concrete examples: Scala is an object-oriented language and as such has classes and methods. A method in Scala is nothing special, you define it as you would define a function, but within a class:

class IntList {
  def append(x: Int): IntList = ???
}

The class represents an immutable list of integers and it has an append` method to return a new list with a new integer appended to the end of the list. Let’s not focus on the implementation, to keep the example to the point. Now, the class can be used in the expected manner:

val l1 = new IntList  // l1 = []
val l2 = l1.append(1) // l2 = [1]
val l3 = l2.append(2) // l3 = [1, 2]
val l4 = l3.append(3) // l4 = [1, 2, 3]

Most object-oriented languages use a similar syntax for defining and calling methods. Scala has a syntactic rule where methods with a single parameter can be used in infix notation. Infix notation is a fancy mathematical term that you can use to flex at parties, but it simply means that the name is used between the receiver and the argument, without additional syntax, just like a mathematical operator. Using this rule, the above could alternatively be written as:

val l1 = new IntList
val l2 = l1 append 1
val l3 = l2 append 2
val l4 = l3 append 3

Not a huge difference, but some people might find the latter more pleasurable to read. It is a general rule that apply to all objects and all methods (as long as they have a single formal parameter). Not many Scala programmers would use this syntax in the above case, as it can make the code actually confusing, but it is a popular syntax when using higher-order functions:

val inc = (x: Int) => x+1
val l5 = l4 map incr // l5 = [2, 3, 4]

Of course, one could also use the syntax l4.map(incr) but it is somewhat of a convention to use the infix notation with higher-order functions as it tends to be more readable (perhaps due to the roots of the notation coming from the likes of Haskell and Caml). In more standard cases like the append function, it is more natural and readable to use the more familiar and consistant object.method(arg) syntax.

Let us look at another example:

class Vector(val x: Double, val y: Double) {
  def plus(that: Vector): Vector = new Vector(this.a + that.a, this.b + that.b)
}
val v1 = new Vector(1, 1)
val v2 = new Vector(2, 3)
val v3 = v1.plus(v2) // v3 = (3, 4)

This is a simple 2D vector and an example of how to use it. It’s very close to how we would write in a language like Java, except for the short constructor syntax. This is also the canonical motivating example for why operator overloading makes sense. Scala supports it, although as a consequence of another feature: flexible syntax for identifiers. In Scala, identifiers are very flexible and, in particular, they can contain any combination of standard symbols (although if they do, they cannot contain any other characers). Taking advantage of that rule, the plus method could be defined more naturally as:

class Vector(val x: Double, val y: Double) {
  def + (that: Vector): Vector = new Vector(this.a + that.a, this.b + that.b)
}

The language treats plus and + in exactly the same way, so the way we use the vector remains the same:

val v1 = new Vector(1, 1)
val v2 = new Vector(2, 3)
val v3 = v1.+(v2)

That is because + is just the name of the method and a method can be used with the object.method(arg) syntax. Of course, here it makes sense to take advantage of the infix notation for methods, and we can actually write:

val v3 = v1 + v2

This is where operator overloading shines: this reads exactly like the mathematical description and the intent could not be clearer.

We have just seen how two independent features — infix notation and flexible syntax for methods — combine elegantly to provide operator overloading. This is just one of many examples where Scala provides common and powerful features from two simpler and well-defined ones. But as this post is getting long, let me take a break there and come back next time dissecting a few more examples.