Wednesday, October 7, 2009

scala tidbits

Some notes taken while reading scala code here and there...


In functional way, even setters should return so that you can write code that looks like
return new Account().setBalance(100).setStatus("active")
instead of
Account acct = new Account()
return acct


@tailrec annotation can be used with method definitions to hint the compiler that implementation is supposed to be tail recursion optimized


I read this code in scala.collections.immutable.Stack class
def pushAll[B >: A](elems: Iterator[B]): Stack[B] =
((this: Stack[B]) /: elems)(_ push _)

It looked so cryptic. Let us see it in pieces

[B >: A] in the type parameter of pushAll means that B has to be a type that A extends.

((this: Stack[B]).. It's simply giving an explicit expected type to an expression (§6.13 of the spec). This is different than a typecast (run-time); if the expression does not conform to the expected type, it will not type-check (compile-time). Lets look at the following example..
scala> trait S
defined trait S

scala> trait T
defined trait T

scala> class A
defined class A

scala> val a = new A with T
a: A with T = $anon$1@fb92dc

scala> (a: S)
:9: error: type mismatch;
found : A with T
required: S
(a: S)
scala> a.asInstanceOf[S]
java.lang.ClassCastException: $anon$1
at .(:9)
at .()
at RequestResult$.(<console>:3)
at RequestResult$.(<console>)
at RequestResult$result()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(
at sun.reflect.DelegatingMethodAccesso...

((this: Stack[B]) /: elems)(_ push _)The Iterator doc says that '/:' is a method defined in this class which is same as foldLeft, since method name ends with ':' so (a /: b)(_ push _) is equal to b./:(a)(_ push _), which in turn is same as b.foldLeft(a)(_ push _).

..(_ push _) This is short form of ((x1: Stack[B], x2: B) => x1.push(x2)), I don't exactly know how it works.


We can create classes that are essentially functions as follow..

abstract class Parser[+T] extends (Input => ParseResult[T])

Here Parser is a function, since it is a function it needs to contain the apply method as following(though in this case its automatically inherited from the "super" function)..

def apply(in: Input): ParseResult[T]


Aliasing this
A clause such as “id =>” immediately after the opening brace of a class template defines the identifier id as an alias for this in the class. For example, in
class A { a =>

a is equivalent to using this in the class. This helps in situations like following..
class Outer { outer => class Inner { ..we can use outer instead of java style Outer.this here... } }
Above mechanism is loosely equivalent to
val outer = this
except outer.method will not be valid, if method was a private member of Outer class, because outer is just another identifier, while in above case of aliasing that would be allowed.


In pattern matching,a binary pattern like A op B is treated as op(A, B).
Similarly in type parameters, P[A op B] is equal to P[op[A, B]]


There is an interesting way of repeating the string in scala. Look at the following code and see how a string of 5 "x" is composed using "*" on String object.
scala> "x" * 5
res14: String = xxxxx

This is possible in scala because "*" is not an operator(in fact scala *does not* have concept of operators) but just another method defined in RichString class that takes a Int and returns String. In this case scala's way of writing method call in a op b certainly looks pleasing. This reminds me that, in scala, I should *think* about the opportunities of using symbolic method names instead of alphabatic ones wherever operator style method calls can look more meaningful.

Found it through longString method of scala.util.parsing.input.Position .

They are a way of wrapping pretty much any data in a way so that pattern matching can be utilized without necessarily making the type of data a case class. This gives one representational independence. In an object, you implement unapply or unapplySeq to make it an Extractors. Many of the collection libraries like List, Array etc provide all the pattern matching functionality using Extractors.


Naming the import:
You can write things like import Fruits.{Apple => McIntosh, Organge} to import just Apple and Orange from Fruits in addition to naming Apple to McIntosh so that we can use McIntosh instead of Apple throughout the code.


Just one observation, scala.List implementation is written heavily in imperative style. May be, the philosophy here is that, what is meant by functional in this context is that for all practical purposes(the external interface used by clients) it is functional but it is OK to write the imperative internal implementation to make it more efficient.


x op= y has a special meaning in scala, it translates into x = x op y provided
1. op= is not defined for x even after trying implicits
2. op is defined for x
3. op is precisely defined in scala specification, but in general it suffices to know its the string of one or more operator characters like +,-,*,++..


No comments:

Post a Comment