Scala for Java programmers

There are many languages that target to the Java Virtual Machine (JVM) -- not just the scripting and dynamically typed ones. How about learning another statically typed language that is compiled JVM and seamlessly integrates to the Java platform? The latest mantra is "One Great VM, Many Languages", Right? :-)

We will look at - Scala? - a functional, object-oriented and concurrent language that runs on the Java platform. Note: this is not a language comparison exercise [i.e., X versus Y comparison to "conclude" which one is better!]. Rather, it is an attempt to give head-start to the Java programmers who want to learn other languages that run on the Java platform. So, the aim is same as it was for my blog past entries such as Java, Groovy and (J)Ruby, Java, JavaScript and Jython - except that we are now looking at a statically typed language...



Feature Java Scala
Static Typing Yes Yes
Object Oriented programming Yes Yes
Functional programming No Yes
Variable declaration

// type var_name = init_value;
int i = 0;


// var var_name: type = init_value;
var i : int = 0;

Constant declaration

// final type var_name = init_value;
final int i = 0;


// val var_name: type = init_value;
val i : int = 0;

Class declaration

class Person {
  // members here
}


class Person {
  // members here
}

Methods

// RetType name(PType1 pName1, PType2 pName2...)

class Person {
  // members here
  public String getName() {
     // code here..
  }

  public void setAge(int age) {
     // code here..
  }
}



// def name(pName: PType1, pName2: PType2...) : RetType 

class Person {
  // members here
  def getName() : String = {
     // code here..
  }

  def setAge(age: int) : unit = {
     // code here..
  }
}

Constructors Method(s) with same name as class name with no return type.

class Person {
    public Person(String name, int age) {
       // initialization here..
    }

    public Person(String name) {
       // call the other constructor
       this(name, 1);
    }
}

Constructor parameters are specified in class declaration itself. Example:

class Person(name: String, age: int) {
   // any method can access "name" or "age" parameter
}

You can have "secondary constructors" as well. Example:

class Person(name: String, age: int) {
   // any method can access "name" or "age" parameter
   def this(name: String) {
       // call the "primary" constructor
       this(name, 1);
   }
}

Operator overloading No. Except that string concatenation can be done using "+" - which gets transformed as "concat" calls. Yes. Just use operator as method name. Example:

class Complex {
  def + (other: Complex) : Complex = {
     //....
  }
}

Also, any single parameter method can be used as an infix operator. Example:

// call System.exit(int) using infix notation
System exit 0
// call Thread.sleep(int) using infix notation
Thread sleep 10

See also: Scala operators
Static fields and methods

class Person {
  private static Person president = ....
  private static Person getPresident() {
     return president;
  }
}


No static members. Use singletons.

Singletons No language support. You can simulate something like this:

class President extends Person {
    // make the constructor private - so that
    // instance can not be created outside of this class
    private President() {}

    // create the singleton object here..
    private static President thePresident = new President();

    // provide accessor for singleton 
    // and add other methods here..
}


object President extends Person {
   // have methods of the singleton object
}

Singleton "objects" are in effect "modules" in Scala. Also, every Java class is viewed like any other Scala class without static methods and fields and a singleton object [whose name is same as Java class name] that contains only the static methods and fields of Java class as it's (non-static) members. This allows accesing static methods of Java classes but at the same time not having static members in Scala.
Inheritance

class Person {
}

class Graduate extends Person {
}


class Person {
}

class Graduate extends Person {
}

See also: Scala subclassing. But, this reference needs update. Now, Java (since JDK 5.0) supports covariant return types.
Calling super class constructor

class Graduate extends Person {
    public Graduate(String name, int age, String degree) {
        super(name, age);
    }
}

You call super class constructor in class declaration itself.

class Graduate(name: String , age: int, degree: String) 
     extends Person(name, age) {
}

Method Overriding

class Graduate extends Person {
  @Override public String getName() {
    // code here...
  } 
}

@Override is optional - but helps with detecting errors (you may be thinking you are overriding - but in fact you may actually be overloading a super class method).

class Graduate extends Person {
  override def getName(): String = {
    // code here...
  }
}

The keyword "override" is mandatory for non-abstract method overrides.
Abstract classes and methods

abstract class Person {
  abstract public String getName();
}


abstract class Person {  
  def getName(): String;
}

No "abstract" keyword for methods. Only for classes.
Root of all reference types java.lang.Object scala.AnyRef - which is same as java.lang.Object in JVM implementation of Scala
Uniform object orientation? (i.e., is everything object?) No. There are primitive types and reference types. But with autoboxing/unboxing, you don't need to explicitly convert b/w primitive types and corresponding box types. Yes. "int" is an alias to "scala.Int" and so on. A bit explanation of type hierarchy. scala.Any is supertype of all types. scala.AnyVal is super type of value types (such as "int" etc.). scala.AnyRef is super type of all "reference" types. But, method calls etc. work on value types as well. Examples:
  • 44.+(4) is same as 44 + 4 where "+" is a method on scala.Int class.
  • Also, single argument methods can be called using "infix" notation just like operator methods are. Example: System exit 4 is same as System.exit(4)
interfaces

interface Runnable {
   void run();
}

Use traits. Traits are like interface but can have method bodies (i.e., not just method declarations). See also: multiple inheritance.

trait Runnable {
  def run(): unit;
}

Multiple inheritance No. Only multiple interfaces may be implemented. Only single class may be extended. Multiple classes can not be extended. Multiple traits can be. And traits can have code -- not just declarations.

trait Runnable {  
   // parameter accepting run method
   def run(obj: AnyRef) : unit;

   // no params - assuming "null" instead
   def run() : unit = {
       System.out.println("assuming null...");
       run(null);
   }
}

// extend a single class, but can "extend"
// multiple traits with "with"

class MyClass extends AnyRef with Runnable {
   // just implement run with param. 
   // Other "run" is inherited from Runnable
   def run(obj: AnyRef) : unit = {
       System.out.println("got " + obj);
   }   
}

See also: Scala mixins, mixins paper, traits paper.
Inner classes

public class Book {
   private String name;
   // ...

   public Order newOrder() {
      ...
   }

   public class Order {
       private Date orderDate;
       private int quantity;
       // ...
   }   
}


class Book(name: String) {          

   class Order(orderDate: Date, 
               quantity : int) {
   }   

   def newOrder() : Order {
       return new Order(new Date(), 1);
   }
}

Unlike Java where such inner classes are members of the enclosing class, in Scala inner classes are bound to the outer object. With the above classes, in Java you can write


// Java
Book freakonomics = new Book("Freakonomics");
Book letUsKillGandhi = new Book("Let us kill Gandhi");
Book.Order o1 = freakonomics.newOrder();
Book.Order o2 = letUsKillGandhi.newOrder();

// You can assign any Book.Order 
// to any other Book.Order

o2 = o1;

// Not in Scala!
val freakonomics: Book = new Book("freakonomics");
val letUsKillGandhi : Book = new Book("Let us kill Gandhi");
var o1 = freakonomics.newOrder();
var o2 = letUsKillGandhi.newOrder();

// this line below will not compile!
// type of "o1" is "freakonomics.Order"
// and type of "o2" is "letUsKillGandhi.Order"

o2 = o1;

In other words, order for "Freakonomics" book can not be treated as instance of order for "Let us kill Gandhi"! If you really want to refer to inner class type as in Java, you can use the following:

var o1 : Book#Order = freakonomics.newOrder();
var o2 : Book#Order = letUsKillGandhi.newOrder();
o1 = o2;

See also: Scala inner classes.
Class literals [section 15.8.2 of JLS].

String.class
Object.class


classOf[String]
classOf[AnyRef]

See also: Scala classOf.
Dynamic type check

x instanceof String
n instanceof Number


x.isInstanceOf[String]
n.isInstanceOf[Number]

Dynamic type cast

String x = (String) obj;
Number n = (Number) obj;


x : String = obj.asInstanceOf[String];
n : Number = obj.asInstanceOf[Number];

Generics

// an interface with a type parameter
interface Stack<E> {
    void push(T t);
    T pop();
    boolean isEmpty();
}

// a class with two type parameters
class Pair<K, V> {
    private K key;
    private V value;
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    // more code...
}


// a trait with a type parameter
trait Stack[E] {
    def push(o: E) : unit;
    def pop() : E;
    def isEmpty(): boolean;
}

// a class with two type parameters
class Pair[K, V](key: K, value: V) {
    // code here...
}

See also: Scala generics.
Generic methods

class Test {
  public <T> List<T> dup(T t, int n) {
    //....
  }
}


class Test {
  def dup[T](x: T, n: Int): List[T] = {
    if (n == 0) Nil
    else x :: dup(x, n - 1)
  }
}

See also: Scala polymorphic methods.
Bounded type parameter

// upper bound
class Foo<E extends SomeType> {
   // ... code here
}

// lower bound
class Foo<E super SomeType> {
  // ...
}

// type parameter in bound
class Stack<E extends Comparable<E>> {
  // ...
}


// upper bound
class Foo[E <: SomeType] {
  // ...
}

// lower bound
class Foo[F >: SomeType] {
  // ...
}

// type parameter in bound
class Stack[E extends Comparable[E]] {
  // ...
}

Wildcards

// upper bound
ArrayList<? extends Number> l = ...

// lower bound
ArrayList<? super Number> l = ...

// wildcard without bound
List<?> list = ...

See also: Wildcards paper
In Java, variance annotations are specified by "clients" [a.k.a use-site]. In Scala, if you want Foo[A] to be subtype of Foo[B] whenever A is subtype of B, you have to declare Foo as

// annotation +T declares type T to be used 
// only in covariant positions.
class Foo[+A] {
  // ...
}


// annotation -T declares type T to be used 
// only in contravariant positions.
class Foo[-A] {
}

Example: In Scala, Lists are immutable and List has covariant annotation. So, List[B] is subtype of List[A] whenever B is subtype of A.

See also: Scala variances
Arrays

String[] s = new String[10];


var s : Array[String] = new Array[String](10);

Array is a generic type in Scala (much like "Vector", "List" etc. in Java are). Note: Arrays do not follow the covariant subtype rule. i.e., Array[Graduate] is not a subtype of Array[Person] even if Graduate is subtype of Person - this is unlike Java language in which Graduate[] is a subtype of Person[].
Array element access, update

int[] a = new int[3];
a[0] = 3;
System.out.println(a[0]);


var a : Array[int] = new Array[int](3);
a(0) = 3;
System.out.println(a(0));

Array element access and update are actually method
calls on Array[T]. You may be wondering how method call
appears on the right side (for element update). No,
Scala does not have C++ style reference (&) types.
a(i) = 10 is translated as a.update(i, 10)
Varargs

class Calc {
   public static int sum(int... values) {
       int res;
       for (int i in values) {
           res += i;
       }
       return res;
   } 
}

// with the above definition, caller can use
Calc.sum(3, 44)
Calc.sum(4, 4, 5,45, 45);

With '...' after type of last parameter, your method becomes variadic. The type of "values" in above example is int[]. In general, the type would be T[], if the last param type was T....

object Calc {
  def sum(values: int\*): int = {
    var res: int = 0;
    for (val v <- values) {
       res = res + 1;
    }
    return res;
  }
}

// With the above definition, caller can use
Calc.sum(3, 44);
Calc.sum(4, 5, 6, 6);

With '\*' for the last parameter, your method becomes variadic. The type of "values" in above example is Seq[int]. In general, the type would be Seq[T], if the last param type was T\*.
Type inference Only for generic methods ( possible future improvements?) Supported everywhere possible. Examples:
  • You can leave types for in var and val. Based on initial value type is inferred.
  • You can leave return type for non-recursive methods as well. Based on return expression return type is inferred.

// int type for "i" inferred
val i = 10;

// String type for "s" inferred
var s = "hello"

// "int" return type inferred
def add(i: int, j:int) = i \* j

// "unit" return type inferred
def sayHello = System.out.println("hello world")

// scala.List[java.lang.String] inferred
var v = List("hello", "world");

// with class Pair[K, V](k: K, v: V) {...}
// Pair[int, String] is inferred for the following.
var p = new Pair(2, "hello");

See also: Scala type inference.
Functions, anonymous functions and closures Not yet. May be in future?. Yes. Can define functions, anonymous functions and closures anywhere -- except in top-level scope (compilation unit level).

// function
def add(i: int, j: int) = i + j

// functions are first-class objects
// accepts a callback function as parameter
def oncePerSecond(callback: ()=>unit): unit = {
   while (true) { callback(); Thread.sleep(1000);
}

def printHello() = {
   System.out.println("hello world");
}

// pass printHello as parameter
oncePerSecond(printHello);

// define anonymous function and call it
((i:int, j:int) => i+j)(3, 4)

// anonymous function passed as parameter
oncePerSecond(()=>System.out.println("hello"));

// nested functions too
def outer() = {
  def inner() = {
     System.out.println("I am inner");
  }
  inner();
}

// inner functions can access outer's locals
// and arguments
def outer(s: String) = {
  def inner() = {
     System.out.println("outer's 's': " + s);
  }
  inner();
}

// Java closure proposals talk about converting
// closures to interfaces automatically. I think
// we can use views in Scala.

// define conversion from any parameterless function 
// to java.lang.Runnable
implicit 
def asRunnable(func : ()=>unit) : Runnable = {
   new Runnable() {
       def run() {
           func()
       }
   }
}

def main ( args : Array[String] ) = { 
    // create a new thread -
    // passing an anonymous function
    // for Runnable
    var t = new Thread(()=>Console.println("hello"));
    t.start();

    // you can now initialize Runnable
    // with any function
    var r : Runnable = ()=>Console.println("I am running!")
    r.run();
} 

See also: Scala views.
List support Use java.util.List and classes implementing it.

// create a List with "List" function (which is actually
// an object with "apply")

var names : List[String] = List("Java", "JavaScript")

// :: is the cons operator
// creates a new list with first element as "Scala"
// and rest of the elements from "names" list
val l = "Scala" :: names

// :: becomes method call on List -- unlike 
// other operators :: takes right-side value 
// as list as target object to call method on!

Lists in Scala are immutable. There are methods on List class - like map, filter etc. that accept closure arguments. Examples:


// make a new list that contains only short names
// shortNames is of type List[String]
var shortNames = names.filter(n=>n.length() < 6)

// make a new list that has lengths of names
// "lengths" is of type List[int]
var lengths = names.map(n=>n.length())

scala.List has covariant type parameter [note: Lists are immutable]. So, List[Graduate] is subtype of List[Person] if Graduate is subtype of Person.

val graduates:List[Graduate] =...
val persons:List[Person] = graduates;

There is much more to Scala - pattern matching, for-comprehension, exception handling, packages, abstract types, XML literals, currying, implicit parameters etc. But, we have had enough for a single blog entry :-)

To be continued.. stay tuned!

Comments:

Are there option types in Scala (like in Nice)? Something like this: var text? = null; Question mark means that value can hold a null and needs to be checked before use. Otherwise assigning null is not possible: var text = null; // Compiler throws exception

Posted by Someone on March 06, 2007 at 01:26 AM IST #

So tell me one thing, dont you think Java packet means j2sdk is going heavier and heavier. Can we have a different download options for this new ADVANCE j2sdk which I guess going to cover 22+ language engine, right now and keep on increasing !!

Posted by Vaibhav on March 06, 2007 at 06:05 AM IST #

On option types (like in Nice): it does not seem that such a facility is available with Scala. Vaibhav: I am sorry I don't get the context of your comment. Would you please clarify?

Posted by A. Sundararajan on March 06, 2007 at 08:42 AM IST #

Yes Sundar, I want to say that all these code go into jdk. As I read jdk 1.7 is going to cover 22 other languages like jruby, jython and all. So, putting all these code in jdk, cant make it too much bulky ? I guess the current size of jdk is something around 60MB(offline installation).

Posted by Vaibhav Choudhary on March 06, 2007 at 09:01 AM IST #

No! I do not think \*all\* these scripting (or otherwise) languages will become part of JDK/JRE!

Posted by A. Sundararajan on March 06, 2007 at 09:13 AM IST #

Scala seems to me to be a great JVM language.

Posted by Robert on March 06, 2007 at 05:30 PM IST #

This is a nice list of differences between Scala and Java. A couple of things: Scala has an Option class which works really well: <code>
def foo(maybe: Option[String]) {
  Console.println("The parameters is "+(maybe getOrElse "Nothing"))
}

def byQuery(where: Option[String], order: Option[String]): String = {
  var query = "SELECT \* FROM foo"
  where.foreach(w => query = query + " WHERE "+w)
  order.foreach(o => query = query + " ORDER BY "+o)
  query
}
</code> There are lots of other things that can be done with Option. Scala supports abstract methods on Traits and Abstract classes: <code>
abstract class Foo {
  def bar: String // I'm abstract
  def baz(in: int): List[String] = List(in.toString) // I'm not abstract
}
</code>

Posted by David Pollak on March 06, 2007 at 06:43 PM IST #

Thanks - really great summary!

Another great thing about Scala, not explicitly mentioned above, is the fact that Scala integrates really nicely with Java. You can implement Java interfaces, extend Java classes, call Java methods, and so on.

An example on the Scala website shows how natural this is.

Posted by Rich Dougherty on March 07, 2007 at 03:20 AM IST #

Hi All: Thank you all for pointing me to the stuff I left out.

Posted by guest on March 07, 2007 at 06:57 PM IST #

Post a Comment:
Comments are closed for this entry.
About

sundararajan

Search

Archives
« January 2012
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder