Showing posts with label Scala. Show all posts
Showing posts with label Scala. Show all posts

08 September 2007

Funny consequences of "functions are objects" rule in Scala

Sorry for another Scala-related post, but I simply couldn't stand. This language is an unique combination of interesting language features and clear and concise syntax which is so rare in the world of programming languages.

Scala is truly object-oriented. This does mean that everything is an object, even functions. Err, functions you'd ask? Yeah, functions are indeed objects but that wasn't a surprise for me because I've seen and used that in Javascript. But function inheritance indeed was a surprise.

How can that be possible? Martin Odersky gives an example that functions with one argument in Scala are objects that mix1

trait Function1[-A, +B] {
def apply(x: A): B
}

Here "-A" means that function that has AnyRef as an argument inherits a function that has a String argument. Take a look at this magical example: ;)

object MyProg {

def doSmthStr(a: String): Int = a.length
def doSmthAny(a: AnyRef): Int = a.hashCode

def compute(function: AnyRef => int) = {
function("Haha")
}

def compute2(function: String => int) = {
function("Haha")
}

def main = {
// not possible because doSmthStr is of type String => int
// which is supertype of AnyRef => int

compute(doSmthStr)

// possible because doSmthAny is exactly of type AnyRef => int
compute(doSmthAny)

// possible because doSmthStr is exactly of type String => int
compute2(doSmthStr)

// possible because doSmthAny is of type AnyRef => int
// which inherits String => int

compute2(doSmthAny)
}
}

MyProg.main

Isn't that cool, the function doSmthAny with AnyRef (aka Object in Java) argument inherits the function doSmthStr with String argument and therefore can be used whenever we need doSmthStr. Amazing!!!

Even more amazing is when the return types in those functions are different. For a function to be the subtype of another function we not only require its argument to be a supertype, but its return value to be a subtype. Citing "Scala by Example" book, function S=>T2 is a subtype of S'=>T' if S' is a subtype of S and T is a subtype of T'.

1
Traits are the Scala implementation of mixins. For C++ guys mixin is just a multiple inheritance. For Ruby guys trait is more like a module (the difference is that in Ruby you'd "include" the module into your class and in Scala you'd "extend" the class with a trait).

2
S=>T is a function defined as:
def function(arg: S): T

More surprises in Scala: covariance and contravariance

I've been reading more about Scala discovering more and more nice features the modern language with static typing can bring. Some of those features look to me just as an syntactic improvement over what we already can do with another statically typed languages like C++. For example, pattern matching example from my last blog is definitely what you can do with several AST classes (they need to have type() or rtti() method) and your own implementation of visitor pattern in C++.

But there're some language features in Scala I didn't expect and didn't think about before. The perfect example IMHO is covariant and contravariant subtyping I discovered for myself just a couple of days before.

Think about this example, if we have class B that inherits class A then we can use objects of type B whenever we need objects of type A. So far so good. But what if we have template class X with A and B as parameter types? C++ tells us X<A> and X<B> are unrelated:

class A {};
class B: public A {};
template class X {};

int main()
{
B *t1 = new B;
A *t2 = t1; //ok because B inherits A

X<B> *x1 = new X<B>;
//error!!! because C++ has non-variant subtyping
// so X<B> and X<A> are different types
X<A> *x2 = x1;
}

Contrary to that, in Scala you can declare that X[B] inherits X[A] and have covariant subtyping or even declare that X[B] inherits X[A] and have contravariant subtyping:

class A {}
class B {}
class X[+Type] {} // +Type means "covariant"

val t1 = new B
val t2 = t1 // ok, B inherits A

val x1 = new X[B]
val x2 = x1 // ok too because X[B] inherits X[A]

return


Not that some elements of covariance and contravariance of types didn't exist before in familiar languages like C++ and Java. Contrary to that they did, but most likely I woulnd't have learned about them if I didn't start learning Scala which directly exposes those things as language features. Cool language Scala is... I must say, very cool ;)

26 August 2007

Scala: a pleasant discovery

I've recently became quite confident that choosing programming language is a process that is very similar to choosing what to cook. First you taste something. If you like it, you eat it. If you really really like it you look for a recipe and try to cook it. Same for the programming language. First you see some code in that language. If you like it, you read more about the language, learn its concepts and ideas. If you really really like what you found, you start programming in that language.

What's interesting is that your consciousness is not usually involved in the tasting phase. On the surface it's simple - you either like new thing or not. But I do believe that there's a serious subconscious process involved here that takes into account all your previous experience and tells you "yes" or "no" to this new thing.

I've made several failed attempts to ignore this subconscious decision and force myself into learning things I don't like. Ironically, such first attempt was Lisp and the last one was Haskell. Needless to say that Lisp still means to me nothing more than lots of isolated, sil^^^... (you know what ;)) and Haskell is still for me nothing more than a pure product of pure mind. Once again, no offense to these languages and people using them. That's just my mind that doesn't allow me to like these great languages ;)

Contrary to that, I made quite a success learning languages I liked. The best examples would be Prolog and Ruby. And yesterday I discovered for me another language I liked from the first look - Scala. So instead of working hard on my projects and my PhD, I spent last two days reading about Scala.

And I should say the language is very cool. It implements an interesting mixture of functional and object-oriented programming paradigms but keeps static typing and very clean syntax. For those familiar with Ruby, I'd say Scala often feels like Ruby that is statically typed, has C-ish syntax and implements more functional programming goodies. I think next time I'll come up with a side-by-side Ruby vs Scala comparison.

And finally a little code snippet for you to taste ;) (from excellent Martin Odersky's "Scala by Example" book)


abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree
case class Var(n: String) extends Tree
case class Const(v: int) extends Tree

type Environment = String => int

object MyProg {
//uses pattern matching to evaluate the expression
def eval(t: Tree, env: Environment): int = t match {
case Sum(l, r) => eval(l, env) + eval(r, env)
case Var(n) => env(n)
case Const(v) => v
}

def main {
val env: Environment = { case "x" => 5; case "y" => 10 }

//(x+x) + (7+y)
var expr: Tree = Sum (Sum(Var("x"), Var("x")), Sum(Const(7), Var("y")))
//(5+5) + (7+10)
println(eval(expr, env)) //prints: 27
}
}

MyProg.main