The current crisis
An interesting phenomenon known as “Andy giveth, and Bill taketh away” comes from the fact that no matter how fast processors become, we software people find a way to use up that speed. There’s a reason for that. With software you’re solving more and more complex problems, and this trend will keep growing. The key question is whether processor manufacturers will be able to keep up with the demand for speed and processor power. When will this cycle end?
End of Moore’s law
According to Moore’s law, the number of transistors per square inch on a chip will double every 18 months. Unfortunately, Intel and other CPU manufacturers are finally hitting the wall with Moore’s law and instead are taking the route of multicore processors. The good news is that processors are going to continue to become more powerful, but the bad news is that our current applications and programming environments need to change to take advantage of multicore CPUs.
Programming for multicores
How can you take advantage of the new multicore processor revolution?
Concurrency. Concurrency will be, if it isn’t already, the way we can write software to solve our large, distributed, complex enterprise problems if we want to exploit the CPU throughputs. Who doesn’t want efficient and good performance from their applications? We all do.
A few people have been doing parallel and concurrent programming for a long time, but it still isn’t mainstream or common among enterprise developers. One reason is that concurrent programming has its own set of challenges. In the traditional thread-based concurrency model, the execution of the program is split into multiple concurrently running tasks (threads), and each operates on shared memory. This leads to hard-to-find race conditions and deadlock issues that can take weeks and months to isolate, reproduce, and fix. It’s not the threads but the shared memory that’s the root of all the concurrency problems. The current concurrency model is too hard for developers to grok, and we need a better concurrent programming model that will help developers easily write and maintain concurrent programs.
Scala takes a totally different approach to concurrency: the Actor model. An actor is a mathematical model of concurrent computation that encapsulates data, code, and its own thread of control and communicates asynchronously using immutable (no side effects) message-passing techniques. The basic Actor architecture relies on a shared-nothing policy and is lightweight in nature. It’s not analogous to a Java thread; it’s more like an event object that gets scheduled and executed by a thread. The Scala Actor model is a better way to handle concurrency issues. Its shared-nothing architecture and asynchronous message-passing techniques make it an easy alternative to existing thread-based solutions.
Traditionally, programming multicore processors is more complex than programming uniprocessors and it requires platform-specific knowledge. It’s also harder to maintain and manage these codebases. To make parallel programming easier, Scala provides higher abstractions in the form of a parallel collections library that hides parallel algorithms. For example, to square up each element of a List in parallel, you can use parallel collections like the following:
List(1, 2, 3).par.map(x => x * x)
In this case the .par transforms the List into a parallel collection that implements the map method using a parallel algorithm. Behind the scenes a parallel collections library will fork threads necessary to execute the map method using all the cores available in a given host machine. The parallel collections library is a new addition to Scala and provides parallel versions of most collection types.
Transitioning from Java to Scala
“If I were to pick a language to use today other than Java, it would be Scala.”
James Gosling
When Java, released in May 1995 by Sun Microsystems, arrived on the programming language scene, it brought some good ideas, such as a platform-independent programming environment (write once, run anywhere), automated garbage collection, and OOP. Java made object-oriented programming easier for developers, compared with C/C++, and was quickly adopted into the industry.
Over the years Java has become bloated. Every new feature added to the language brings with it more boilerplate code for the programmer; even small programs can become bloated with annotations, templates, and type information. Java developers are always looking for new ways to improve productivity using third-party libraries and tools. But is that the answer to the problem? Why not have a more productive programming language?
Scala improves productivity
Adding libraries and tools to solve the productivity problem sometimes backfires, adding complexity to applications and reducing productivity. I’m not saying that you shouldn’t rely on libraries; you should whenever it makes sense. But what if you had a language built from the ground up from ideas like flexibility, extensibility, scalability—a language that grows with you?
Developers’ needs today are much different than they used to be. In the world of Web 2.0 and agile development, flexibility and extensibility in the programming environment are important. Developers need a language that can scale and grow with them. If you’re from Java, then Scala is that language. It will make you productive, and it will allow you to do more with less code and without the boilerplate code.
Scala does more with less code
To see the succinctness of Scala, you have to dive into the code. The next two listings provide a simple example of finding an uppercase character in a given string, comparing Scala and Java code.
Finding an uppercase character in a string using Java
boolean hasUpperCase = false;
for(int i = 0; i < name.length(); i++) {
if(Character.isUpperCase(name.charAt(i))) {
hasUpperCase = true;
break;
}
}
In this code you’re iterating through each character in the given string name and checking whether the character is uppercase. If it’s uppercase, you set the hasUpperCase flag to true and exit the loop. Now let’s see how we could do it in Scala.
In Scala you can solve this problem with one line of code. Even though it’s doing the same amount of work, most of the boilerplate code is taken out of the programmer’s hands. In this case you’re calling a function called exists on name, which is a string, by passing a predicate that checks whether the character is true, and that character is represented by _. This demonstrates the brevity of the Scala language and its readability. Now let’s look at the following listing, where you create a class called Programmer with the properties name, language, and favDrink.
Defining a Programmer class in Java
public class Programmer {
private String name;
private String language;
private String favDrink;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getFavDrink() {
return favDrink;
}
public void setFavDrink(String favDrink) {
this.favDrink = favDrink;
}
}
This is a simple POJO (plain old Java object) with three properties—nothing much to it. In Scala you could create a similar class in one line, as in the following listing.
Defining a Programmer class in Scala
class Programmer(var name:String,var language:String,var favDrink:String
In this example you’re creating a similar class called Programmer in Scala but with something called a primary constructor (similar to a default constructor in Java) that takes three arguments. Yes, you can define a constructor along with the class declaration—another example of succinctness in Scala. The var prefix to each parameter makes the Scala compiler generate a getter and setter for each field in the class. That’s impressive, right? For now, it’s clear that with Scala you can do more with fewer lines of code. You could argue that the IDE will automatically generate some of this boilerplate code, and that’s not a problem. But I’d argue that you’d still have to maintain the generated code. Scala’s succinctness will be more apparent when you look into much more involved examples. In Java and Scala code comparisons, the same feature requires 3 to 10 times more lines in Java than Scala.
Coming from a dynamic language
It’s hard to find developers these days who haven’t heard of or played with Ruby, Groovy, or Python. The biggest complaint from the dynamic language camp about statically typed languages is that they don’t help the productivity of the programmer and they reduce productivity by forcing programmers to write boilerplate code. And when dynamically typed languages are compared with Java, obvious things like closures and extensibility of the language are cited everywhere. The obvious question here is how Scala is different.
Before going into the issue of static versus dynamically typed languages, let’s look into Scala’s support for closures and mixin. The following listing shows how to count the number of lines in a given file in Ruby.
Counting the number of lines in a file in Ruby
count = 0
File.open “someFile.txt” do |file|
file.each { |line| count += 1 }
end
You’re opening the file someFile.txt and for each line incrementing the count with 1. Simple! The following listing shows how you can do this in Scala.
Counting the number of lines in a file in Scala
val src = scala.io.Source.fromFile(“someFile.txt”)
val count = src.getLines().map(x => 1).sum
The Scala code looks similar to the Ruby code. You could solve this in many ways in Scala; here you’re using the map method to return 1 for each line, then using the sum method to calculate the total count.
Scala supports mixin composition with something called traits, which are similar to an abstract class with partial implementation. For example, you can create a new type of collection which allows users to access file contents as iterable, by mixing the Scala Iterable trait. The only contract is to implement an iterator method:
class FileAsIterable {
def iterator = scala.io.Source.fromFile(“someFile.txt”).getLines()
}
Now if you mix in the Scala Iterable, your new FileAsIterable will become a Scala Iterable and will start supporting all the Iterable methods:
val newIterator = new FileAsIterable with Iterable[String]
newIterator.foreach { line => println(line) }
In this case you’re using the foreach method defined in the Iterable trait and printing each line in the file.
Scala version 2.10 adds support for a Dynamic[10] type. Using this feature you can dynamically add methods and fields to a type at runtime. This is very similar to the method_missing feature of Ruby and is quite useful if you’re building a domain-specific language (DSL). For example, Scala map is a collection of key value pairs and if you want to access the value associated with a key you can do something like the following:
val someMap = Map(“foo” -> 1, “bar” -> 2)
someMap.get(“foo”)
Here someMap is a collection of two key value pairs and someMap.get(“foo”) will return 1. Using Dynamic we can easily change that so that we can access the keys as if they were part of a type:
class MyMap extends Dynamic {
…
def selectDynamic(fieldName: String) = map.get(fieldName)
private val map = Map(“foo” -> “1”, “bar” -> 2)
}
val someMap = new MyMap
someMap.foo
someMap.bar
The magic ingredient in this case is the selectDynamic method. (Scala methods are defined using the def keyword.) When the Scala compiler checks that foo is not part of the type it doesn’t give up immediately. If the type is a subtype of Dynamic it looks for the selectDynamic method and invokes it. If the method is not provided, you will get a compilation error.
Scala also supports something called implicit conversion, which is similar to Ruby open classes but scoped and compile time checked
Case for static typing, the right way
With all that said and done, Scala is still a statically typed language. But if you’ve gone through the examples in the previous section, you’ve probably already figured out that Scala’s static typing doesn’t get in your face, and it almost feels like a dynamically typed language. But still, why should you care about static typing?
he size and the complexity of the software you’re building are growing every day, and having a compiler do the type checking for you is great. It reduces the time you need to spend fixing and debugging type errors. In a statically typed language like Scala, if you try to invoke a length method on a number field, the Scala compiler will give you a compilation error. In a dynamically typed language you’ll get a runtime error.
Another benefit of a statically typed language is that it allows you to have powerful tools like refactoring and IDEs. Having an IDE might not interest you because of powerful editing tools like Emacs and TextMate, but having refactoring support is great when working on large codebases.
All these benefits do come with a price. Statically typed languages are more constraining than dynamically typed languages, and some force you to provide additional type information when you declare or call a function. But having constraints is useful when building a large application because they allow you to enforce a certain set of rules across the codebase. Scala, being a type-inferred language, takes care of most of the boilerplate code for the programmer (that’s what compilers are good for, right?) and takes you close to a dynamically typed language, but with all the benefits of a statically typed language.
To demonstrate how type inference works, create an array of maps in Scala:
val computers = Array(
Map(“name” -> “Macbook”, “color” -> “white”),
Map(“name” -> “HP Pavillion”, “color” -> “black”)
)
If you run this Scala code in the Scala REPL, you’ll see the following output:
computers:
Array[scala.collection.immutable.Map[java.lang.String,java.lang.String]]
= Array(Map(name -> Macbook, color -> white), Map(name -> HP Pavillion,
color -> black))
Even though you only specified an array of maps with key and value, the Scala compiler was smart enough to deduce the type of the array and the map. And the best part is that now if you try to assign the value of name to some integer type variable somewhere in your codebase, the compiler will complain about the type mismatch, saying that you can’t assign String to an integer-type variable.
For the programming language enthusiast
One of the main design goals for Scala was to integrate functional and OOP into one language (see section 1.1.4 for details). Scala is the first statically typed language to fuse functional and OOP into one language for the JVM. Scala has made some innovations in OOP (mentioned previously) so that you can create better component abstractions.
Scala inherits lots of ideas from various programming languages of the past and present. To start with, Scala adopts its syntax from Java/C# and supports both JVM and Common Language Runtime (CLR). Some would argue that Scala’s syntax is more dissimilar than similar to that of Java/C#. You saw some Scala code in previous sections, so you can be the judge of that. In Scala every value is an object, and every operation is a method call. Smalltalk influences this pure object-oriented model. Scala also supports universal nesting and uniform access principles (see the following listing), and these are borrowed from Algol/Simula and Eiffel, respectively. In Scala variables and functions without parameters are accessed the same way.
Universal access principles in Scala
class UAPExample {
val someField = “hi”
def someMethod = “there”
}
val o = new UAPExample
o.someField
o.someMethod
Here you’re accessing a field and a method of the instance of the UAPExample class, and to the caller of the class it’s transparent.
Scala’s functional programming constructs are similar to those of the metalanguage (ML) family of languages, and Scala’s Actor library is influenced by Erlang’s Actor model.
Based on this list you may realize that Scala is a rich language in terms of features and functionality. You won’t be disappointed by Scala and will enjoy learning this language.
References:
Scala in Action
By: Nilanjan Raychaudhuri