Each time I learn a new language, I learn something about
programming. When I learned Java as a C++ programmer, for example,
Java's interface construct taught me the value of multiply inheriting
from pure abstract base classes. Although this style of programming was
possible in C++, I didn't think about multiple inheritance this way in
my C++ days, and I didn't use abstract base classes much in my C++
designs. Once I began programming in Java, however, I started using the
style all the time. Learning about Java—in particular, its
interface construct—changed how I approached OO design.
A similar effect has happened as I've learned to program in Scala.
In the past two years I've worked quite a bit with Scala, a new
statically typed language for the Java Platform that fuses
object-oriented and functional programming concepts. Scala allows me to
write code that's almost as concise as Ruby or Python. I can call into
Java libraries, including my existing Java libraries, from Scala as
easily as I can from Java. Given that Scala is statically typed, I enjoy
the
benefits of static typing such as types as documentation, code
completion in IDEs, deterministic refactoring, and execution speed. (The
performance of Scala programs is about the same as Java programs.) But
Scala also gives me concise and type-safe ways of accessing some of the
benefits traditionally associated with dynamic languages, such as the
ability to add new methods to existing classes, or to pass types that
don't share a common hierarchy to a method.
How did Scala change how I think about programming? In short: I learned
to appreciate the functional style. The functional style of programming
emphasizes immutable objects, variables that can be initialized but not
reassigned (final variables in Java), transformation of data structures,
and methods and control constructs that result in a value but have no
side effects. At the other end of the spectrum is the imperative style,
which is characterized by mutable objects, variables that can be
reassigned (normal variables in Java), indexing through data structures,
and methods and control constructs with side-effects.
Although Scala is often touted as a functional programming language, it
is not exclusively functional. Scala supports both functional and
imperative styles. You can, if you choose, program in Scala much the
same way you program in Java, which is likely a predominantly imperative
style. This helps ease the Scala learning curve, but as you get more
familiar with Scala, you might find yourself preferring functional
alternatives. I did. Why? I discovered that functional style code tends
to be more concise and less error prone than the corresponding
imperative style code. Functional style code is often higher level,
which makes it quicker to write and easier to read. As an example,
consider this Java code, which determines whether a string contains an
upper case character:
boolean nameHasUpperCase = false; // This is Java
for (int i = 0; i < name.length(); ++i) {
if (Character.isUpperCase(name.charAt(i))) {
nameHasUpperCase = true;
break;
}
}
The imperative style is in evidence here, because the
nameHasUpperCase
variable is reassigned as a side effect of the for loop, which iterates
through the characters in the string by indexing. You can achieve the
same result more concisely in Java like this:
boolean nameHasUpperCase = !name.toLowerCase().equals(name);
This line of Java code exhibits a more functional style, because it
transforms immutable data: the name
string is transformed
to another, different string that is all lower case, then that value is
transformed to a boolean result. In addition, the
nameHasUpperCase
variable is initialized, but at least in
this snippet of code, not reassigned. It would be more clearly
functional if the variable were final.
In Scala, you could write code similar to the previous two examples, but
the most idiomatic way to write this in Scala is:
val nameHasUpperCase = name.exists(_.isUpperCase)
The nameHasUpperCase
variable is declared as a
val, a variable that can be initialized but not reassigned
(similar to a final variable in Java). Even though no explicit type
annotations appear in this example, Scala's type inference mechanism
assigns type Boolean to nameHasUpperCase
. The
exists
method iterates through a collection of objects and
passes each element in turn to the passed function object. Here, the
name
string is being treated as a collection of characters,
so exists will pass each character of the string to the function. The
_.isUpperCase
syntax is a function literal in Scala, a
shorthand way to write a bit of code that can be passed around and
invoked. The underscore stands for the function's lone parameter. You
can think of the underscore, therefore, as a blank that's filled in each
time the function is invoked. If the exists
method finds
that the function returns true for one of the passed characters—i.e.,
that one of the characters is upper case—it returns true. Otherwise it
returns false.
Although the last one-liner may look cryptic to someone not familiar
with Scala, once you know Scala, you'll be able to see at a glance the
purpose of this code. By contrast the other two versions will take just
a bit more study. Another difference to note is that a potential
off-by-one error exists in the imperative example, because you must
explicitly indicate the upper index to which to iterate. This error
can't happen in the functional versions, and in this way, the functional
versions are less error prone.
Lastly, I want to point out that I did not turn "completely
functional" when I went to Scala. Although I've found that functional
style code is most often more concise, clearer, and less error prone,
I've also found that that sometimes the imperative style leads to
clearer, more concise code. In such cases I use it. Scala allows me to
use both imperative and functional styles easily, to combine them in the
way I find most optimal for the clarity of the code.