Scala for Java programmers - Part 2

This is continuation of my last blog entry titled Scala for Java programmers.
Feature Java Scala
Application Any Java class with public static void main(String[]) method can be run as an application.

public class Hello {
  public static void main(String[] args) {
    System.out.println("hello world");
  }
}

Any object with def main(args: Array[String]) : unit method can be run as an application. [Note: Scala does not have static members - you have to use singleton objects.]

object Hello {
  def main(args: Array[String]) : unit = {
    Console.println("hello world");
  }     
}

Also, you could extend Application class and have just code inside object like in

object Hello extends Application {
  Console.println("hello world");
}

But, if you want command line parameters, you have to use the first option.
Sequence-comprehension is an easier syntax to build a new sequence from existing sequence(s) by filtering, mapping or combination of those. Use Java's for-each loop and build a new list.
General form:
for(<generators>; <filter>) yield <expression>


Example:

object Main extends Application {

  val list = List("Fortran", "Java", "Scala", 
                  "JavaScript", "ML");
  val shortList = 
    for (val e <- list; e.length() < 6) 
    yield e.toUpperCase()
  Console.println(shortList);
}

You could accomplish everything above by "map", "filter", "flatMap" calls on List(s). For-comprehension provides an easier syntax to work with. In the above case, we could have written

object Main extends Application {

  val list = List("Fortran", "Java", "Scala", 
                  "JavaScript", "ML");
  val shortList = list.filter(e=>e.length() < 6)
                      .map(e=>e.toUpperCase());
    
  Console.println(shortList);
}

See also: Sequence Comprehensions.
Method references No. Use java.lang.reflect.Method (but, you'll miss static type checking!) Method references can be passed as argument whenever a function type value is expected.

object Main {
  def func(s: String) : boolean = {
    return s.startsWith("J");
  }

  def print(s: String): unit = {
    Console.println(s);
  }

  def main(args: Array[String]) : unit = {
    var list = List("hello", "world", "Java");

    // pass method reference as argument
    list = list.filter(func);
    Console.println(list);

    // explicitly mentions "Main" object
    // in the method reference
    list.foreach(Main.print);
  }
}

Also, remember operators are methods too and numbers are objects too! So, the following works:

object Main {
  def main(args: Array[String]) : unit = {
    val list = List(3, 54, -1, -324, 45);
    // print negative numbers only
    Console.println(list.filter(0 >));
  }
}

Pattern Matching is a techique to classify objects by their run-time type, accessing their mebers or some other characteristic of group of objects. No. Following "Matching Objects with Patterns", in Java you could do:
  • Object-oriented decomposition
  • Visitor pattern
  • Type-Test/Type-Cast (instanceof and cast)
Scala has "match" expression. Think of it as a generalization of Java's switch statement. While Java's switch statement works only for integers and enums, Scala's pattern matching is more general. Simple switch statement equivalent in Scala is as follows:

object t {
   def main(args: Array[String]) : unit = {
     args.length match {
         case 1 => Console.println("1 argument");
         case 2 => Console.println("2 arguments");
         case _ => Console.println("more than 2!");
     }
   }
}

More complex match example:
  def matchTest(x: Any): Any = x match {
    // matching integer value "1"
    case 1 => "one"
    // matches string "two"
    // x is a string with "two" as value
    case "two" => 2
    // x is any int type but with not equal to 1
    case y:Int => "scala.Int"
  }
Even more complex pattern matchings involve case classes. Case classes are classes with "case" modifier. With "case" classes, you can
  • create objects of case classes without "new" operator - use function call-like syntax
  • case classes have automatic accessor generators for constructor parameter.
  • case classes can be used in pattern matching.
Example:

abstract class Expression;
case class Number(n:int) extends Expression;
case class Add(left:Expression, right:Expression) extends Expression;
case class Var(name: String) extends Expression;
case class Multiply(left:Expression, right:Expression) extends Expression;

// sample match expression that uses above case classes

// This expression simplifies a given expression "e"
// We use x + 0 = x and x \* 1 = x rules to simplify

def simplify(e: Expression) : Expression = {
  e match {

    // matches if expression is a Multiply object
    // and right operand is Number 1
    case Multiply(x, Number(1)) => x

    // matches if expression is a Add object
    // and right operand is Number 0
    case Add(x, Number(0)) => x

    // matches any other expression - no simplification
    // just return the original expression
    case _ => e
  }
}


References: See also: Scala case classes and Scala pattern matching.
Throwing exceptions

throw new RuntimeException();
throw new IOException();


throw new RuntimeException();
throw new IOException();

This is same as Java except that in Scala, there are no checked exceptions. User is not forced to have "throws" clauses as in Java.
Catching Exceptions

try {
   // ...
} catch(IOException ieExp) {
   // ...
} catch(RuntimeException re) {
   // ...
} finally {
   // ...
}

where finally is optional.

try {
     // ...
} catch {
  case ioExp:IOException => {
     // ...
  }
  case re:RuntimeException => {
     // ...
  }
} finally {
  // ...
}

Notes:
  • Pattern matching is used to match a particular exception type within a single catch clause - unlike separate catch clauses in Java.
  • finally clause is optional here as well.
  • Because catch uses case clauses, it is possible to match values - for example, if your exception class is a case class, then you can match constructor parameters of your exception class as well.

case class MyException(s:String) extends Exception(s) {
}
object Hello extends Application {
  try {
    throw new MyException("hello");
  } catch {
    // MyException with message equal to "hello"
    case MyException("hello") =>
      Console.println("world!");
    // MyException with message not equal to "hello"
    case MyException(_) => 
      Console.println("no way!");  
    // any other exception
    case _ => 
      Console.println("any other exception");
  }
}

Packages

package com.acme;

With the above statement as first line in a compilation unit, everything in the compilation unit goes into the package

package com.acme;

With the above statement as first line in a compilation unit, everything in the compilation unit goes into the package -- as in Java. But, Scala supports "packaging" statements as well. The following example defines


package com.acme {
  class X {}
  class Y {}
}

package com.sun {
  class X {}
  package P {
    class Y {}
  }
}

Notes:

  • Several packages may be declared in the same compilation unit.
  • Packages can include other packages.
The above example defines com.acme, com.sun, com.sun.P packages.

See also: Scala packages.
Import Statements

// import whole package
import java.io.\*;

// import a specific (public) class from a package
import java.net.URL;


// import whole package
import java.io._;

// import a specific (public) class from a package
import java.net.URL;

Static Import

// import all static members of Math class
import static java.lang.Math.\*

No statics in Scala -- we use singleton objects. But, we can import all members of singleton objects.

object t {
  def sayHello() : unit = {
     Console.println("hello");
  }
}

object Main {
  import t._;
  def main(args: Array[String]): unit = {
    sayHello();
  }
}

Also, every Java class is exposed a Scala class without static members and an object that contains only the static members of the Java class. So, it is possible to import all static members of a Java class using the object import as follows:

import java.lang.Math._;

object t {
 def main(a: Array[String]) : unit = {
  Console.println(sin(3.14/2));
 } 
}

typedefs (a.k.a type aliasing). No (but may be in future?)

Generic pattern is 

type <name> =  <type-expression>

Examples:

type StringList = List[String];
var sl: StringList = List("hello", "world");

type voidFunc = ()=>unit;
var v : voidFunc = ()=>Console.println("hello");
v();


Abstract Types (using abstract type members in classes in addition to abstract value members) No. Use generics! In Scala, classes can have type members in addition to value members. Also, like value members (say a method being abstract), type members could be abstract as well. Example:

abstract class Cell {
  // an abstract type member
  // subclass can define it
  type T

  // abstract value member
  var element: T
}

abstract class ValueCell extends Cell {
  // define T to be some subtype of AnyVal
  type T <: AnyVal
}

class IntCell extends Cell {
  // define T to be int
  type T = int

  // define (initial) value to be zero
  var element : T = 0
}

See also: Scala Abstract Types.
Currying Not supported A method or function can have multiple parameter-sections or segments. Each parameter section can be curryed. Example:

object Main {
  def main(args: Array[String]) : unit = {
    def sum(x: int)(y: int) : int = x + y
    // curry sum to specify first value
    val add7 = &sum(7)
  
    // call curried version with one argument
    Console.println(add7(8));
  }
}
Notes:
  • define with multiple parameter sections so that it can be curried.
  • Normal call would look like sum(7)(8)
  • Each parameter section can have it's own variadic parameter - i.e., you could have each parameter section ending with T\* type.
The following example accepts multipled ints and multiple strings as parameters.

def printAges(values: int\*)(names: String\*) : unit = {
  // code here..
}

// caller calls this as
printAges(34, 24, 45)("X", "Y", "Z");

Call-by-name Not supported.

object Main {
  def func(v: => int) = {
      Console.println("You passed " + v);
      Console.println("You passed " + v);
  }

  def main(args: Array[String]): unit = {
      var i = 0;
      func({i = i + 1; i});
  }
}

Without "=>" before "int", you would get the output
You passed 1
You passed 1
But, with the "=>", you would get the output
You passed 1
You passed 2

Interesting blog entry to simulate Java-style for(<init< <condition> <update>) loop for Scala is here. The author uses call-by-name parameters to implement control abstraction.

XML Literals No (may be in future?) XML literals are supported.

object Main {
  def main(args: Array[String]): unit = {
      var s = <html>
              <title>{args(0)}
              </title></html>;
              
      Console.println(s);
  }
}

Possible to mix Scala expressions in XML literals - as shown in above example (within {} args[0] is referred). XML elements may be used inside pattern-matching as well (only elements).

See also: Scala XML Processing, <scala/xml>
Comments:

About import statements: renaming is possible inside import selectors (see Scala reference, section 4.7, p. 40ff); for example:


object Main extends Application {
  import java.util.{BitSet => JBitSet}
  import scala.collection.mutable.{BitSet => MBitSet}
  import scala.collection.immutable.BitSet
  val set1 = new JBitSet(8)
  val set2 = new MBitSet(8)
  val set3 = new BitSet(8, 8, Array(4), false)
  set1.set(2)
  set2 += 2
  Console.println("set1 = " + set1)  // set1 = {2}
  Console.println("set2 = " + set2)  // set2 = Set(2)
  Console.println("set3 = " + set3)  // set3 = Set(2)
}

Posted by S. Micheloud on March 07, 2007 at 12:43 PM IST #

S. Micheloud: Thank you for that info - I'm still learning Scala (I started very recently). Thanks again!

Posted by A. Sundararajan on March 07, 2007 at 12:55 PM IST #

Very interesting blog post. Will definitely look up Scala.

Posted by Krishnan on March 07, 2007 at 09:56 PM IST #

About throwing exceptions: Java programmers using Scala code can be forced to have "throws" clauses in their code using a Scala annotation; for example:


// File: Reader.scala
class Reader(fname: String) {
  import java.io._
  private val in = new BufferedReader(new FileReader(fname))
  @throws(classOf[IOException])
  def read() = in.read()
}

// File: Test.java
import java.io.IOException;
public class Test {
    public static void main(String[] args) { // throws IOException {
        Reader rd = new Reader("Test.java");
        int ch;
        while ((ch = rd.read()) != -1) {
            System.out.print((char) ch);
        }
    }
}

Compiling Test.java will produce the following error message:


Test.java:6: unreported exception java.io.IOException; must be caught or declared to be thrown
        while ((ch = rd.read()) != -1) {
                            \^
1 error

Simply uncomment the "throws" clause to compile and run the example !

Posted by S. Micheloud on March 09, 2007 at 08:12 AM IST #

S. Micheloud: Thanks again! BTW, did you have chance to look at my (next) post on Scala singleton posts. Could you please clarify or point me to the right reference?

Posted by A. Sundararajan on March 09, 2007 at 08:55 AM IST #

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

sundararajan

Search

Archives
« April 2014
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
   
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder