You know who you are. You’re the developer who picked up Java years
ago, maybe as a second language and better alternative to C++, maybe as
your first language coming into the industry. You’re comfortable with
Java, you know its ins and outs, its moods. It’s like an old
girlfriend; you may not feel the vibe anymore, but you know just how to
rub it so it smiles. In short, you’re a craftsman, and Java is your
workhorse tool.
You’re starting to to become a bit pragmatic about your language
choice though. To put it mildly, the Java honeymoon is over. While you
can hardly find enough fault with the language to just walk away,
you’re certainly open-minded enough to consider alternatives. You’ve
heard of this new-fangled thing called Ruby – how could you
not
have heard, given the sheer noise level produced by its followers.
You’re impressed by the succinctness of its constructs and the power of
its syntax, but you’re not sold on the idea of using a scripting
language to build your enterprise app. Dynamic typing and TextMate are
all well and good, but for the real-world iron horse you’re going to
need something with a bit more backbone. As a good pragmatist, you
stick with the tool that works: Java.
The good news is that there’s light at the end of the tunnel.
There’s a new language on the scene that’s taking the developer world by
storm. Scala seems to offer everything you’ve been looking for in a
language: static typing, compiled to bytecode (so you can run it on all
those ancient Java-capable servers), a succinct and expressive syntax.
You’ve seen a few examples which have really caught your eye. It looks
the spitting image of Java, except with half the useless constructs
thrown out. No semi-colons, no
public static void method qualifiers; it even seems to have some sort of static type inference mechanism.
The only problem you have now is figuring out where to start. You’ve
tried looking on the Scala website, but what you found stopped you in
your tracks. Everything’s so…functional. Lamdas, high-order functions,
immutable state, recursion out the wazoo. Suddenly things are looking
less promising.
Have no fear, ye refugee of Java EE grid iron, all is not lost.
True, Scala is a functional language, but it’s also imperative and
highly object oriented. What does this mean? It means that you don’t
have to write code with the sole purpose of pleasing
Haskell Curry.
You can write code that you can actually read a week from now. You may
even be able to show this code to your Java-loving coworkers and they
just might understand it. You don’t
have to curry every function and avoid loops at all costs. You
can write your Java applications in Scala. You just need the right introduction.
Introductions
If you’re like me and can identify with the above, then this series
is for you. I’ve read a lot of articles and tutorials on Scala (
Alex Blewitt’s series
is highly recommended, especially if you’re interested in the more
functional side of life), but few of these tutorials have even attempted
to make things easier for the run-of-the-mill Java developer to make
the transition. I personally have very little FP (Functional
Programming) experience, so I don’t think I could write an article about
porting Scheme code to Scala even if I wanted to. Instead, this series
will focus on how Scala is just like Java, except better.
Did I mention
Alex’s Scala introduction series?
Seriously, this is great reading, and not a bad introduction to Scala
in and of itself. Once you’re done reading my ramblings, you should run
over and read some of his more coherent stuff. The more the merrier!
Getting Started
| object HelloWorld extends Application {
println("Hello, World!")
}
|
Nothing like getting things rolling with a little code. Notice the refreshing lack of mandatory semicolons. We
can
use them anyway, but they aren’t required unless we need multiple
statements on a single line. This code sample does exactly what it
looks like, it defines an application which (when run using the
scala interpreter) will print “Hello, World!” to stdout. If you put this code into a file with a
.scala extension, you can then compile it using the
scalac compiler. The result will be a single
.class file. You could technically run the
.class using the
java interpreter, but you would have to mess with the classpath a bit. The easiest thing to do is just use the
scala command like so:
| scalac hello.scala
scala HelloWorld
|
Notice the name of the file in question? Unlike Java, Scala doesn’t
force you to define all public classes individually in files of the same
name. Scala actually lets you define as many classes as you want per
file (think C++ or Ruby). It’s still good practice to follow the Java
naming convention though, so being good programmers we’ll save our
HelloWorld example in a file called “HelloWorld.scala”.
Editors
Just a brief note on your first few moments with Scala: using the
right editor is key. As you must have learned from your many years in
the Java world, IDEs are your friend. Scala, being a much younger
language doesn’t have very good IDE support yet. It is a static,
general purpose language like Java, so IDE support will be forthcoming.
For the moment however, you’re stuck with a very limited set of
options.
- Eclipse (using one of two shoddy and unstable Scala plugins)
- Emacs
- IntelliJ (basically just syntax highlighting support)
- TextMate
- VIM
- jEdit
There are a few other options available, but these are the biggies
(to see a full list, look in the misc/scala-tool-support/ directory
under the Scala installation root). My personal recommendation is that
you use jEdit or TextMate, though if you’re feeling adventurous you’re
free to try one of the Eclipse plugins too. Scala support in Eclipse
has the advantage (at least with the
beta plugin)
of features like semantic highlighting, code completion (of both Scala
and imported Java classes) and other IDE-like features. In my
experience though, both Eclipse plugins were unstable to the point of
unusable and as such, not worth the trouble. Scala is a much cleaner
language than Java, so it really does have less of a need for a super
powerful IDE. It would be nice, no question about that, but
not essential.
More Hello World
| object HelloWorld2 {
def main(args:Array[String]) = {
var greeting = ""
for (i <- 0 until args.length) {
greeting += (args(i) + " ")
}
if (args.length > 0) greeting = greeting.substring(0, greeting.length - 1)
println(greeting)
}
}
|
Save this in a new file (we’ll call it “HelloWorld2.scala”), compile and run using the following commands:
| scalac HelloWorld2.scala
scala HelloWorld2 Hello, World!
|
Once again, this prints “Hello, World!” to stdout. This time we did
things a little differently though. Now we’ve got command line
arguments coming into our app. We define a variable of type
String,
iterate over an array and then call a bit of string manipulation.
Fairly straightforward, but definitely more complex than the first
example. (
Note: Scala mavens will no doubt suggest the use of
Array#deepMkString(String) (similar to Ruby’s
Array::join method)
instead of iterating over the array. This is the correct approach, but
I wanted to illustrate a bit more of the language than just an obscure
API feature).
The first thing to notice about this example is that we actually define a main method. In the first example, we just extended
Application
and declared everything in the default constructor. This is nice and
succinct, but it has two problems. First, we can’t parse command line
args that way. Second, such examples are extremely confusing to Scala
newbies since it looks more than slightly magical. Don’t worry, I’ll
explain the magic behind our first example in time, but for now just
take it on faith.
In the example, we define a main method that looks something like our old Java friend,
public static void main.
In fact, this is almost exactly the Scala analog of just that method
signature in Java. With this in mind, an experienced developer will be
able to pick out a few things about the language just by inspection.
First off, it looks like all methods are implicitly public. This is somewhat correct. Scala methods are public
by default, which means there’s no
public method modifier (
private and
protected are both defined). It also looks like Scala methods are static by default. This however, is not entirely correct.
Scala doesn’t really have statics. The sooner you recognize that,
the easier the language will be for you. Instead, it has a special
syntax which allows you to easily define and use singleton classes
(that’s what
object means). What we’ve really declared is a singleton class with an instance method,
main. I’ll cover this in more detail later, but for now just think of
object as a class with only static members.
Upon deeper inspection of our sample, we gain a bit of insight into
both Scala array syntax, as well as an idea of how one can explicitly
specify variable types. Specifically, let’s focus on the method
declaration line.
| def main(args:Array[String]) = {
|
In this case,
args is a method parameter of type
Array[String]. That is to say,
args is a string array. In Scala,
Array
is actually a class (a real class, not like Java arrays) that takes a
type parameter defining the type of its elements. The equivalent Java
syntax (assuming Java had an
Array class) would be something like this:
| public static void main(Array<String> args) {
|
In Scala, variable type is specified using the
variable:Type syntax. Thus, if I wanted to declare a variable that was explicitly of type
Int, it would be done like this:
If you look at the sample, we actually do declare a variable of type
String.
However, we don’t explicitly specify any type. This is because we’re
taking advantage of Scala’s type inference mechanism. These two
statements are semanticly equivalent:
In the first declaration, it’s obvious to us that
greeting is a
String, thus the compiler is able to infer it for us. Both
greetings are staticly type checked, the second one is just 7 characters shorter.
Observant coders will also notice that we haven’t declared a return type for our
main
method. That’s because Scala can infer this for us as well. If we
really did want to say something explicitly, we could declare things
like this:
| def main(args:Array[String]):Unit = {
|
Once again, the type antecedes the element, delimited by a colon. As an aside,
Unit is the Scala type for I-really-don’t-care-what-I-return situations. Think of it like Java’s
Object and
void types rolled into one.
Iterating Over an Array
| var greeting = ""
for (i <- 0 until args.length) {
greeting += (args(i) + " ")
}
|
By the way, it’s worth noting at this juncture that the convention
for Scala indentation is in fact two spaces, rather than the tabs or the
four space convention that’s so common in Java. Indentation isn’t
significant, so you can really do things however you want, but the other
four billion, nine hundred, ninety-nine million, nine hundred,
ninety-nine thousand, nine hundred and ninety-nine people in the world
use the two space convention, so it’s probably worth getting used to
it. The logic behind the convention is that deeply nested structure
isn’t a bad sign in Scala like it is in Java, thus the indentation can
be more subtle.
This sample of code is a bit less intuitively obvious than the ones
we’ve previously examined. We start out by declaring a variable,
greeting of inferred type
String.
No hardship there. The second line is using the rarely-seen Scala for
loop, a little more type inference, method invocation on a “primitive”
literal and a
Range instance. Developers with Ruby experience will probably recognize this equivalent syntax:
| for i in 0..(args.size - 1)
greeting += args[i] + " "
end
|
The crux of the Scala for loop is the
Range instance created in the
RichInt#until method. We can break this syntax into separate statements like so:
| val range = 0.until(args.length)
for (i <- range) {
|
Oh, that’s not a typo there declaring range using
val instead of
var. Using
val, we’re declaring a variable
range as a constant (in the Java sense, not like C/C++
const). Think of it like a shorter form of Java’s
final modifier.
Scala makes it possible to invoke methods using several different syntaxes. In this case, we’re seeing the
value methodName param syntax, which is literally equivalent to the
value.methodName(param) syntax. Another important action which is taking place here is the implicit conversion of an
Int literal (0) to an instance of
scala.runtime.RichInt. How this takes place isn’t important right now, only that
RichInt is actually the class declaring the
until method, which returns an instance of
Range.
Once we have our
Range instance (regardless of how it is created), we pass the value into the magic
for syntax. In the
for loop declaration, we’re defining a new variable
i of inferred type
Int.
This variable contains the current value as we walk through the range
[0, args.length) - including the lower bound but not the upper.
In short, the
for loop given is almost, but not quite equivalent to the following bit of Java:
| for (int i = 0; i < args.length; i++) {
|
Obviously the Java syntax is explicitly defining the range tests, rather than using some sort of
Range object, but the point remains. Fortunately, you almost never have to use this loop syntax in Scala, as we'll see in a bit.
The body of the loop is the one final bit of interesting code in our sample. Obviously we're appending a value to our
greeting String.
What I'm sure struck you funny (I know it did me) is the fact that
Scala array access is done with parentheses, not square brackets. I
suppose this makes some sense since Scala type parameters are specified
using square brackets (rather than greater-than/less-than symbols), but
it still looks a little odd.
To summarize, the upper sample in Scala is logically equivalent to the lower sample in Java:
| var greeting = ""
for (i <- 0 until args.length) {
greeting += (args(i) + " ")
}
|
| String greeting = "";
for (int i = 0; i < args.length; i++) {
greeting += args[i] + " ";
}
|
A Better Way to Iterate
In Java 5, we saw the introduction of the so-called for/each iterator syntax. Thus, in Java we can do something like this:
| for (String arg : args) {
greeting += arg + " ";
}
|
Much more concise. Scala has a similar syntax defined as a
high-order function - a function which takes another function as a
parameter. I'll touch on these more later, but for the moment you can
take it as more magic fairie dust:
| args.foreach { arg =>
greeting += (arg + " ")
}
|
Here we see that
foreach is a method of class
Array that takes a closure (anonymous function) as a parameter. The
foreach method then calls that closure once for each element, passing the element as a parameter to the closure (
arg). The
arg parameter has an inferred type of
String because we're iterating over an array of strings.
Now as we saw earlier, Scala methods can be called in different ways. In this case we're calling
foreach omitting the parentheses for clarity. We also could have written the sample like this:
| args.foreach(arg => {
greeting += (arg + " ")
})
|
Scala actually defines an even
more concise way to define
single-line closures. We can omit the curly-braces altogether by moving
the instruction into the method invocation:
| args.foreach(arg => greeting += (arg + " "))
|
Not bad! So our fully rewritten sample looks like this:
| object HelloWorld2 {
def main(args:Array[String]) = {
var greeting = ""
args.foreach(arg => greeting += (arg + " "))
if (args.length > 0) greeting = greeting.substring(0, greeting.length - 1)
println(greeting)
}
}
|
The syntax looks great, but what is it actually doing? I don't know
about you, but I hate having to use APIs that I don't know how to
replicate myself. With a bit of work, we can recreate the gist of the
Scala
foreach method in pure Java. Let's assume for a moment that Java had an
Array class. In that
Array class, let's pretend there was a
foreach method which took a single instance as a parameter. Defined in code, it might look like this:
| public interface Callback<T> {
public void operate(T element);
}
public class Array<T> {
// ...
public void foreach(Callback<T> callback) {
for (T e : contents) { // our data structure is called "contents"
callback.operate(e);
}
}
}
|
I could have defined
foreach recursively (as it is defined
in Scala), but remember I'm trying to keep these explanations clear of
the tangled morass that is FP.
Sticking with our goal to see an analog to the Scala
foreach, here's how we would use the above API in Java:
| public class HelloWorld2 {
public static void main(Array<String> args) {
final StringBuilder greeting = new StringBuilder();
args.foreach(new Callback<String>() {
public void operate(String element) {
greeting.append(element).append(' ');
}
});
if (args.length() > 0) {
greeting.setLength(greeting.length() - 1);
}
System.out.println(greeting.toString());
}
}
|
Starting to see why Scala is legitimately appealing? If you're like
me, you just want Scala to be a more concise Java. In this case, that's
exactly what we've got. No strange functional cruft, no immutable
state. Just solid, hard-working code.
A Word About Built-in Types
Because Scala is built on the JVM, it inherits a lot of its core API
directly from Java. This means you can interact with Java APIs. More
than that, it means that
any code you write in Scala is using Java APIs and functions. For example, our sample
HelloWorld2 is using a string variable
greeting. This variable is literally of type
java.lang.String. When you declare an integer variable (type
Int) the compiler converts this to the Java primitive type
int.
It's also worth noting that there are a number of built-in implicit conversions (just like the
Int to
RichInt we saw earlier with the
Range creation). For example, Scala's
Array[String] will be implicitly converted to a Java
String[]
when passed to a method which accepts such values. Even Scala type
parameters are available and interoperable with Java generics (in the
current development version of Scala and slated for inclusion in
2.6.2). In short, when you use Scala you’re really using Java, just
with a different syntax.
Conclusion
Scala doesn’t have to be complex, needlessly academic or require a
master’s degree in CompSci. Scala can be the language for the common
man, the 9-5 developer who’s working on that next enterprise web
application. It has real potential to provide the clear syntax Java
never had without forsaking the power and stability of a trusted,
first-class language. Convinced?
Up next, classes, methods and properties: everything you need to know to get rolling with
object-oriented programming in Scala.
(codecommit)
0 comments: on "Scala for Java Refugees Part 1: main(String[])"
Post a Comment