Monday, September 15, 2014

Scala Crib Sheet #2

More Scala for Java programmers:

Case statements as functions

In Akka's sample.hello.HelloWorld:

  def receive = {
    // when the greeter is done, stop this actor and with it the application
    case Greeter.Done => context.stop(self)
  }

"Case sequences as partial functions: A sequence of cases (i.e. alternatives) in curly braces can be used anywhere a function literal can be used. Essentially, a case sequence is a function literal, only more general." [1]

Partial Functions

Not to be confused with partially applied functions, this borrows from the mathematical concept of a partial function where not all values in the domain map to other values (this contrasts with a total function). An example of a partial function in mathematics is the log function over all real numbers. Clearly, negative real numbers do not map to any real numbers.

Following on from the idea above of case statements as more generalized functions, then a case statement that does not cover every eventuality is a partial function. The Scala compiler will issue a warning but will not abort compilation of this (although you might get runtime errors).

Taking this example in the Scala docs:

    val isEven: PartialFunction[Int, String] = {
        case x if x % 2 == 0 => { println(x) ; x+" is even" }
    }

we can see that this is indeed a partial function as it doesn't return anything in the event x is odd.

All the other nice functionality that Scala gives you for this class is added by the compiler. For instance, I didn't implement the isDefinedAt function but the compiler did it for me:

$ javap -c ./target/scala-2.10/classes/com/phenry/scala/MyScala\$\$anonfun\$1.class
.
.
  public final boolean isDefinedAt(int);
    Code:
       0: iload_1       
       1: istore_2      
       2: iload_2       
       3: lookupswitch  { // 0
               default: 12
          }
      12: iload_2       
      13: iconst_2      
      14: irem          
      15: iconst_0      
      16: if_icmpne     23
      19: iconst_1      
      20: goto          24
      23: iconst_1      
      24: ireturn 
.
.

which when JADed, becomes:

    public final boolean isDefinedAt(int x1)
    {
        int i = x1;
        boolean flag;
        if(i % 2 == 0)
            flag = true;
        else
            flag = false;
        return flag;
    }


Type parameter hints

In Akka's sample.hello.HelloWorld:

    // create the greeter actor
    val greeter = context.actorOf(Props[Greeter], "greeter")

which calls:

  /**
   * Scala API: Returns a Props that has default values except for "creator" which will be a function that creates an instance
   * of the supplied type using the default constructor.
   */
  def apply[T <: Actor: ClassTag](): Props = apply(defaultDeploy, implicitly[ClassTag[T]].runtimeClass, List.empty)


Unlike Java, Scala can instantiate objects from type parameters. "What's required here is that you help the compiler by providing a runtime hint of what the actual type parameter is ... This means following the type with a a colon and the class name ClassManifest."  [1]. Since Programming in Scala was published, this ClassManifest has been deprecated in favour of ClassTag which is what we see here. It carries the type information that was erased at compile time.

This adding of an implicit parameter is called a context bound.

"Implicits in subclasses and subobjects take precedence over implicits in base classes." [1]

[1] Programming in Scala, Odersky.

No comments:

Post a Comment