read


read
or learn more

Groovin’ with Scala

Oct 20, 2008

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

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())

        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

 
import java.util._

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

 
import java.util._

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

 
import java.util._

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

 
import java.util._

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?

object Clutter {                                             
    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

 
object Clutter {                                               
    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

 
object Cleaner {                                      
    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

object Cleaner {                                       
    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

  
object Cleaner {                                       
    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

  
object Cleaner {                                       
    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

 
object Cleaner {                                       
  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)

val names = List("Mike", "Marvin", "Bhagat", "Horacio")
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

  1. 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 &lt;= 4) foreach(s =&gt; println(s))

    Second, the function parameter in foreach can be omitted:

    names filter(_.length &lt;= 4) foreach(println)

  2. Jorge,

    Thanks for the post. I added your snippets to my original presentation and will use it for my meeting today. :)

    -m

Reply to “Groovin’ with Scala”