Groovin’ with Scala
I have been attempting to introduce some low-ceremony programming tools and languages to my programming team at my job and thanks to a series of brown-bags and internal discussions have sold Scala for use in an upcoming project. It wasn’t functional programming, type-inference, case classes, or even the Actor Model that was the biggest win but instead embeddable XML and the fact that Twitter uses it… hey, whatever works right?
I have looked into Scala for a few months and on occasion attempted to put together a nice example of how it compares to Java. However, it turns out that Jim Weirich from Compuware presented a nice example for Groovy that I decided to steal and mangle to work for Scala (standing on the shoulders of giants and all that). The results are below, but bear in mind that it works much better as a presentation. Nonetheless…
Caveat emptor: I am still learning Scala, so I have yet to absorb its idioms, terminology, and nuances
Original Java Class
import java.util.*;
class Clutter {
public static void main( String[] args) {
List names = new ArrayList();
names.add( "Mike");
names.add( "Marvin");
names.add( "Bhagat");
names.add( "Horacio");
System.out.println( names);
Clutter e = new Clutter();
List short_names = e.filterLongerThan( names, 4);
System.out.println( short_names.size());
for( String s : short_names) {
System.out.println( s);
}
}
public List filterLongerThan( List strings, int length) {
List result = new ArrayList();
for( String s : strings ) {
if( s.length() < length+1) {
result.add( s);
}
}
return result;
}
}
There are no semi-colons and the package wildcard is different in Scala
import java.util._
class Clutter {
public static void main( String[] args) {
List names = new ArrayList()
names.add( "Mike")
names.add( "Marvin")
names.add( "Bhagat")
names.add( "Horacio")
System.out.println( names);
Clutter e = new Clutter()
List short_names = e.filterLongerThan( names, 4)
System.out.println( short_names.size())
for( String s : short_names) {
System.out.println( s)
}
}
public List filterLongerThan( List strings, int length) {
List result = new ArrayList()
for( String s : strings ) {
if( s.length() < length+1) {
result.add( s)
}
}
return result
}
}
Iterating over a list is elegant
class Clutter {
public static void main( String[] args) {
List names = new ArrayList()
names.add( "Mike")
names.add( "Marvin")
names.add( "Bhagat")
names.add( "Horacio")
System.out.println( names);
Clutter e = new Clutter()
List short_names = e.filterLongerThan( names, 4)
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
public List filterLongerThan( List strings, int length) {
List result = new ArrayList()
strings.foreach { s =>
if( s.length() < length+1) {
result.add( s)
}
}
return result
}
}
Let type-inference take care of most of those type annotations, plus Scala doesn’t need the new
keyword
class Clutter {
public static void main( args:Array[String]) {
val names = List()
names.add( "Mike")
names.add( "Marvin")
names.add( "Bhagat")
names.add( "Horacio")
System.out.println( names);
val e = Clutter()
var List short_names = e.filterLongerThan( names, 4)
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
public List filterLongerThan( List strings, int length) {
List result = ArrayList()
strings.foreach { s =>
if( s.length() < length+1) {
result.add( s)
}
}
return result
}
}
It should not be this difficult to create a list of strings
class Clutter {
public static void main( args:Array[String]) {
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
System.out.println( names);
val e = Clutter()
var List short_names = e.filterLongerThan( names, 4)
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
public List filterLongerThan( List strings, int length) {
List result = new ArrayList()
strings.foreach { s =>
if( s.length() < length+1) {
result.add( s)
}
}
return result
}
}
Filtering can be handled using a for-comprehension
class Clutter {
public static void main( args:Array[String]) {
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
System.out.println( names);
val e = Clutter()
var List short_names = e.filterLongerThan( names, 4)
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
public List filterLongerThan( List strings, int length) {
for( n <– strings if( n.length <= length)) yield n
}
}
The filtering can occur locally and does not need to be part of a class
class Clutter {
public static void main( args:Array[String]) {
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
System.out.println( names);
var List short_names = for( n <– names if( n.length <= 4)) yield n
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
}
Why not make our class a singleton?
public static void main( args:Array[String]) {
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
System.out.println( names);
List short_names = for( n <– names if( n.length <= 4)) yield n
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
}
There are no statics in Scala
def main( args:Array[String]) {
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
System.out.println( names);
List short_names = for( n <– names if( n.length <= 4)) yield n
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
}
}
We really do not need a main at all, instead make our filter a library function
def filterLongerThan( names:List[String], len:int) = {
for( n <– names if( n.length <= len)) yield n
}
}
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
System.out.println( names);
var List short_names = Cleaner.filterLongerThan( names, 4)
System.out.println( short_names.size())
short_name.foreach( s => System.out.println( s) )
System.out.println is way too long
def filterLongerThan( names:List[String], len:int) = {
for( n <– names if( n.length <= len)) yield n
}
}
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
println( names);
var List short_names = Cleaner.filterLongerThan( names, 4)
println( short_names.size())
short_name.foreach( s => println( s) )
Functional style prefers we reduce the number of explicit bindings
def filterLongerThan( names:List[String], len:int) = {
for( n <– names if( n.length <= len)) yield n
}
}
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
println( names);
Cleaner.filterLongerThan( names, 4) foreach( s => println(s))
Scala objects are self-reflexive and therefore evaluate to themselves
def filterLongerThan( names:List[String], len:int) = {
for( n <– names if( n.length <= len)) yield n
}
}
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
names
Cleaner.filterLongerThan( names, 4) foreach( s => println(s))
Idiomatic Scala style is 2 spaces per indent
def filterLongerThan( names:List[String], len:int) = {
for( n <– names if( n.length <= len)) yield n
}
}
val names = List("Mike", "Marvin", "Bhagat", "Horacio")
names
Cleaner.filterLongerThan( names, 4) foreach( s => println(s))
Why not just use the internal filter function and remove the function param to the println.
(thanks Jorge)
names.filter(_.length <= 4) foreach(println)
So there you have it, Scala vs. Java using a pseudo-realistic example — now, if I could only sell them on Clojure. (Although Stuart Halloway may get a call)
-m
2 Comments, Comment or Ping
Jorge Ortiz
Great post! I love the process of gradual transformation. It’s a great way to show all the improvements without overwhelming someone all at once.
This can be even shorter, though. First, “filter” is already a method defined on all Scala collections:
names filter(_.length <= 4) foreach(s => println(s))
Second, the function parameter in foreach can be omitted:
names filter(_.length <= 4) foreach(println)
Oct 20th, 2008
fogus
Jorge,
Thanks for the post. I added your snippets to my original presentation and will use it for my meeting today. :)
-m
Oct 21st, 2008
Reply to “Groovin’ with Scala”