|
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>
|
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 08:43 PM IST #
Posted by A. Sundararajan on March 07, 2007 at 08:55 PM IST #
Posted by Krishnan on March 08, 2007 at 05:56 AM 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 errorSimply uncomment the "throws" clause to compile and run the example !
Posted by S. Micheloud on March 09, 2007 at 04:12 PM IST #
Posted by A. Sundararajan on March 09, 2007 at 04:55 PM IST #