Why Java Folks Should Look Forward to Scala
There’s an interesting series of blog posts in progress: Why Java folks should stop looking down on C# : Part 1 and Part 2 (at the point of time of writing this post). It offers an interesting and detailed set of contrasts between Java and C#. It is a detailed analysis and makes for very worthwhile reading. What really intrigued me was this comment :
“We notice that Java developers generally tend to look scornfully at C#, as a copycat created by Microsoft and used by dummies. In theses blog series, I am going to try to sweep this nonsense and show some of the C# goodness.”
At least in my experience, I do not recollect Java developers looking scornfully at C# (notice that I did not mention .NET or Windows or Microsoft – I said C#). But perhaps there are some out there and the blog series does attempt to provide them sufficient evidence to reconsider their opinions. But reading through the posts made me think, there’s at least one good reason Java programmers can choose to celebrate and look forward to rather than feel worried about Java. And all these capabilities are available for the asking on their preferred platform – the JVM and in an interoperable and incrementally migratable way from their current code bases. – Scala.
Now, believe me you, scala capabilities extend far beyond those I describe below. But that further discovery is an adventure which readers are encouraged to conduct later. Also – I am only a little along that path of Scala discovery and still have distances to cover. So I won’t feel surprised if people are able to offer healthier and superior solutions to the ones I describe below. In fact, I would encourage them to do the same. But here’s something for all ye java citizens to feel good about.
Please note that it will be helpful if you review these two blog posts referred to above – since almost every example I refer to below, that I write using Scala, is based on the examples in these posts which are written in Java and C#. Thus, even after reading those posts, it might be useful to keep them open in other tabs. So that should you prefer to do so, you can refer to those Java and C# examples simultaneously as you read the Scala examples.
Unified Type System
Scala has types for the java primitives eg. Byte, Short, Int. Thus you can continue to deal with them as objects instead of having to specifically deal with them as primitives. All value classes inherit from AnyVal, whereas all others inherit from AnyRef, both in turn inheriting from Any. In addition there are a number of additional methods that are available on these types (eg. RichInt). At the same time these types have exactly the same ranges as java primitives. Thus the scala compiler can choose to transform instances of such value types into corresponding Java primitive types.
Farewell Checked Exceptions
Goodbye. Adios. Au revoir, Vale. Checked Exceptions have been bid farewell. And I don’t think anyone’s less happy for it. But if you need to call Scala code from Java, you can choose to use the @throws annotation to mark your methods so that java code may treat these as thrown exceptions.
Double Rainbow Accessors
Another heavy weight boilerplate thats been waived goodbye is java bean style getter setters. Every non private member declared automatically gets a getter and setter free by default. In situations where you would want to override the default behaviour, you can choose to do so as well. Besides a particular construct called a case class further simplifies this and helps you create a class trivially with reasonable implementation of equals, toString etc. already rolled in. It is likely, that new keyboards continue to retain their gloss and continue to function far longer when coding in scala than in Java. A simple example of double rainbow accessors :
case class Meme (var catchPhrase : String, var url: String)
// Notice: class members are declared as default constructor parameters. No further
// declaration required again.
class MemeAdvanced (private [this] var cp: String, private [this] var u: String){
// Since these are private fields, they can be wrapped using
// getters / setters as follows which can be modified to suit any non-typical
// expectations eg. validations
// if the above parameter declarations did not have private qualifier,
// the methods below would be automatically provided, whereas if declaration contained
// val instead of var, only the getter would get provided.
def catchPhrase = cp
def catchPhrase_=(s: String) {cp = s}
def url = u
def url_=(s: String) { u = s}
}
object DoubleRainbow {
def main(args : Array[String]) : Unit = {
// using case classes
var meme = new Meme("foo","bar")
meme.catchPhrase = "Rick roll'd"
meme.url = ""
println(meme.catchPhrase)
// using normal classes
var meme2 = new MemeAdvanced("foo","bar")
meme2.catchPhrase = "Rick roll'd"
meme2.url = ""
println(meme.catchPhrase)
}
}
Initialisers
There’s a bunch of new initialisation capabilities eg. initialising using field names
var meme = new Meme(catchPhrase="blub", url="blub2")
println(meme.catchPhrase)
or you can initialise a collection by passing a series of arguments to the constructor
val digits = List[Int](0,1,2,3,4,5,6,7,8,9)
or you could choose to load up a map with a bunch of associations at instantiation time
val keywordsMapping = Map[String,String] ( "super" -> "base", "boolean" -> "bool", "import" -> "using" )
println(digits.head + " " + keywordsMapping("boolean"))
Verbatim (Multiline) Strings
That isn’t too hard with scala too. Just use triple consecutive double quotes delimiter (“”")to make the string span multiple lines.
val input = """Multiline
325-532-4521"""
println(input)
Methods as first class citizens
Missing function pointers after you moved away from C / C++? Thats available too .. in a typesafe manner.
// declare a function pointer which takes a string as an input
// and outputs the same
var normalizeOp = (input: String) => input reverse;
println(normalizeOp("abcd"))
// compiler error : normalizeOp = (input: String) => 0;
// thus the type of normalizeOp can no longer be changed
// but it can be used to point to a different method instead
normalizeOp = (input: String) => input trim;
println(normalizeOp(" foo bar "))
Event
Now, scala doesn’t have a built in Event class which has its automatic hardwired publish subscribe capabilities. But one of the themes you will find in this post is that Scala lives up to its name which really refers to it being a scalable language. So a whole set of language constructs can actually be built into the language by writing other code. Thats why sometimes it feels somewhat like a meta-language, a language to write your own language structures in. The construct below is rather simple and straight-forward, but we shall see creating your own language control structure like constructs later as well.
Here’s a simple event class
class Event {
var l = List[() => Unit]()
def +=(f: () => Unit): Unit = l = f :: l
def apply() = l map (_())
}
It declares a list of listeners l and allows listening functions to be registered against the event getting triggered (which in this case would be the += method. Finally since the event is triggered using event() construct in C#, we here define the apply function, which will get triggered whenever e() is invoked, e being the instance of any event. Note: I’ve deliberately used single character names for the fields to allow you to focus on the other constructs – not a good coding practice.
class Button {
val action = new Event();
def performClick() = onClick()
private def onClick() = {
// this should call the apply() method
action()
}
}
object EventDriver {
def performAction() {
println("Work!")
}
def main(args : Array[String]) : Unit = {
val button = new Button()
// add a method as a listener
button.action += performAction
// trigger the event
button.performClick()
}
}
So does one really need to have a Event baked into the language ? Apparently not really when it is a scalable language.
Lambda expressions
Indeed one of the strong points of this language. A simple lambda function is given below
def isUniverseAnswer = (x: Int) => x == 42
println(isUniverseAnswer(42))
println(isUniverseAnswer(43))
There, it isn’t so hard. But what when you want to define a lambda on the fly ? Turns out thats quite straight forward too.
val users = List[User](User("Five",5), User("Fifteen",15), User("TwentyFive", 25), User("Ten",10), User("Twenty", 20)) // Note : the argument passed to the filter() method is the lambda, and the _ refers // to each User object passed in println (users filter (_.age < 18))
And if we did want to explore closures, there’s good support there too.
var counter = 0
val action = () => {counter += 1; println("counter = " + counter)}
action()
action()
As Jack Sparrow would’ve said, “savvy?”
Extension methods
The exact details of how some of these capabilities are made to work are beyond the scope of this post, but scala allows for a lot of new extension methods on basic built in types through a variety of additional classes, and the same capabilities can be used by you to define any additional extension methods. As a teaser example, we’ll use the reverse method defined in the WrappedString type which helps extend the same method to be used with strings.
Return Multiple Values
Thats very intuitive and simple too.
object ReturnMultiple {
// this method returns two values
def addOneToAll(a: Int, b: Int) = (a + 1, b + 1)
def main(args : Array[String]) : Unit = {
val (c, d) = addOneToAll(3,4)
println(c + "," + d)
}
}
Null-coalescing operator
To the best of my knowledge scala doesn’t have this operator. The C# code looks like follows which allows the first non-null value amongst a, b, and c to be set as the result.
string result = a ?? b ?? c
Well, we’ll build that operator (I’m sure someone will suggest a better option than the one below)
class Nullable(val t: AnyRef) {
def ??(b: AnyRef) = if (this.t != null) this.t else b
}
object NullCoalescing {
implicit def objToNullable(a: AnyRef) : Nullable = { new Nullable(a) }
def main(args : Array[String]) : Unit = {
println("hello" ?? null ?? null)
println((null: AnyRef) ?? "world" ?? null)
println((null: AnyRef) ?? null ?? "foobar")
}
}
If you see the three println statements, they show how the newly defined ?? operator can deliver the same semantics. Since null cannot help the type inferencing engine, in the latter two println statements – it has been explicitly cast to AnyRef.
Automatic Resource Management
Apparently C# has a built in capability of automatic resource management by using the keyword using. Alas Scala doesn’t. But building it is hardly much effort. So here goes :
import java.io.FileInputStream
import java.io.DataInputStream
import java.io.InputStreamReader
import java.io.BufferedReader
object AutomaticResourceManagement {
// This is a structural type. Any type which has methods which match the two
// desired signatures specified below can be used wherever this type is expected
// ** no inheritance required **
type ReadableAndCloseable = { def close(): Unit ; def readLine() : String}
// And to be able to define our own control structure, the second parameter to
// using takes a function block which takes a ReadableAndCloseable as input
// and returns nothing.
def using(resource: ReadableAndCloseable)(f: ReadableAndCloseable => Unit) {
try {
f(resource)
} finally {
println("Closing resource")
resource.close()
}
}
def main(args : Array[String]) : Unit = {
val reader = new BufferedReader(new InputStreamReader(new DataInputStream(new FileInputStream("foo.txt"))))
// Now you can be sure, the reader will get closed.
using(reader){
(resource) => println("First line is: " + resource.readLine())
}
}
}
Summary
Well there’s more in Scala. Lots more. And it takes some patient
effort to learn it. We’ve hardly started to talk about the functional
programming capabilities. Or its parallel collections. Or for that
matters its pattern matching. Or even its ability to deal with Generics
with specified Co and Contravariance. We haven’t gone that far. But all
the seemingly distant capabilities – that seemed to be miles away in a
different planet called .NET and a country called C#, are actually just a
step away – using Scala. As a java programmer, I don’t think you should
look down at C# .. just look forward to Scala
From
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)
Erik Post replied on Tue, 2011/05/31 - 6:22am
val digits = List(0,1,2,...), which looks a bit nicer. You may also omit the 'new' operator when using case classes, which is good for nested expressions, e.g. val tree = Tree(Leaf("left"), Leaf("right")). Much less clutter.
Tomasz Nurkiewicz replied on Tue, 2011/05/31 - 2:19am
Erik Post replied on Tue, 2011/05/31 - 6:13am
Alessandro Santini replied on Tue, 2011/05/31 - 7:39am
in response to:
Tomasz Nurkiewicz
Dhananjay Nene replied on Tue, 2011/05/31 - 8:58am
in response to:
Erik Post
Dhananjay Nene replied on Tue, 2011/05/31 - 8:59am
in response to:
Alessandro Santini
Dhananjay Nene replied on Tue, 2011/05/31 - 9:05am
in response to:
Erik Post
Mike P(Okidoky) replied on Tue, 2011/05/31 - 1:16pm
Erik Post replied on Tue, 2011/05/31 - 5:28pm
in response to:
Dhananjay Nene
Note that typically, nulls would only arise in dealing with Java code, and there are a couple of ways of shielding your Scala code from them. There's a lot more coolness to the Option type of course, but this might be a starting point. Cheers and thanks for the article!
Steve Mcjones replied on Wed, 2011/06/01 - 7:14am
in response to:
Mike P(Okidoky)
@Mike: People have told you quite a few times already how Scala does it, why it is that way and why people using Scala prefer it.
You may like that reason, you may not.
But really, coming back after months (which you could have used to learn and verify what people explained to you) with the exact same uninformed whining?
People like you are the reason why I think not everyone should have write-permission on the intertubes.
Mike P(Okidoky) replied on Wed, 2011/06/01 - 3:59pm
I think purposely keeping this out is ridiculous.
And Steve, people like you is what makes Javalobby such a bitchy place to hang around with. Result: notice how little actual brainstorming happens here. Right, practically none. Nothing but articles with 0 replies, with noone wanting to engage. We have people like you to thank for that.
I'm sure you'll have some other condescending or belittling remark for this.