May 30, 2008

Adventures in Scala: Part II

My first impressions of Scala: It's different. I have a feeling a lot of Java programmers will hate this language. And it is not a newbie language, I would recommend knowing at least one functional language before tacking this. Preferably one with static-typing, like Haskell or ML.

This is my first experience with a type-inferenced imperative language. In fact, I can't really think of any other type-inferenced imperative languages, since the only languages I can think of that use type-inferencing are functional languages.

The documentation and community around it is still fairly small, as is expected. The tutorials on their site seem to be more oriented toward language features and the differences from Java. This is nice and all, but is there differences in the libraries, for example I/O?

So in trying to learn Scala, my first project was something I did in university in a Java class: build an interpreter for TML (tiny machine language). TML is a simple RISC-style assembly language. There are a few registers (I put 8) and some memory (I put 1024 bytes). You have basic commands like load, add, jmp, etc. and labels to make jumping easier. And there are comments.

The little things I found are this:
  • The difference between var and val. Both are used to declare a variable, but from what I've seen in my short escapade is that variables declared with val are immutable (const).

  • Array syntax: You use parentheses instead of square brackets to do array access. Odd, but not hard to adapt to.

  • Generics: This was a bit more interesting. The square brackets are used to specify the type instead of angle brackets:
    var list = new LinkedList[String]()
    As with the array syntax, this isn't so bad, you just need to adapt to it. However there are some issues with the type inferencing in situations like this:
    var list = new LinkedList()
    In Java, this would default to being a linked list that holds values of type Object. In Scala, this means that the list holds values of type Unit. The Unit type is equivalent to void in C/C++/Java. So this list can only hold the one possible object of type Unit: (). Pretty useless! So you have to specify which type of objects you want in the list, even if that type is Object. Little annoying.

  • Keeps Java standard libraries: So I still have to go
    var input = new BufferedReader(new FileReader(stdin))
    when I want to read input from the console. At least I don't have to put try..catch around it. So it's slightly less annoying than Java. Note that I did try to look around a bit to see if Scala made this easier, but I couldn't really find anything. Might just be that I'm lacking Google skills.

  • Complicated: It has a lot of Java's features, plus a ton more. Singleton classes, case classes, functional-type things, etc. Not sure if this is a good thing or a bad thing, but we'll see.
So far, the language is a huge improvement on Java, but still too Java-like for me to really love the language. I'll still try and work with Scala, but I find myself still preferring C++ when I need a language with structure.

4 comments:

James Iry said...

> This is my first experience with a type-inferenced imperative language

It's imperative in the same way that ML is imperative - or functional in the same way that ML is functional. Both are "impure" functional languages. I.e. both allow mutable variables and IO at any spot in your program.

Of course, Scala tends to rely on Java libraries so you'll end up using it more imperatively than you would ML.

> This is nice and all, but is there differences in the libraries, for example I/O?

Scala's libraries add things like actors, parser combinators, and functional collections. Unfortunately, IO is pretty under-represented in the libraries right now.

> The difference between var and val. Both are used to declare a variable, but from what I've seen in my short escapade is that variables declared with val are immutable (const).

Val is not quite the same as C++ const. I.e. you can't declare that you have a mutable reference to an immutable object. If you know Java, "val" is more the equivalent of putting "final" in front of a variable declaration - it makes the reference immutable. There has been some talk about having a const like system for Scala, but there's some concern that the complexity cost for const is too high compared to the guarantees it actually provides.

> var list = new LinkedList()
> In Java, this would default to being a linked list that holds values of type Object

In Java 1.5+ that issues a compiler warning and is considered bad style vs saying "new LinkedList<Object>()".

>In Scala, this means that the list holds values of type Unit.

The equivalent of Object in Scala is "AnyRef" or "Any" depending on the context. But, in your above example you get a list of Nothing, which means there are no values that are valid, not even (). Nothing is the bottom type and it's not explicitly denotable in C++ or Java. Anyway, I admit that getting a LinkedList[Nothing] is useless and I would much prefer a warning or error with invariant structures. But the thing is it does make sense if you use Scala's standard immutable List which is covariant.

scala> val list = List()
list: List[Nothing] = List()

scala> val list2 = 4::list
list2: List[Int] = List(4)

> var input = new BufferedReader(new FileReader(stdin))

The Scala standard IO libraries are pretty sad right now so it's drop to Java time. However, there's a library called Scalax that is attempting to address that and other shortcomings. The plan is to move the best bits of Scalax into the standard library over time.

> Complicated: It has a lot of Java's features, plus a ton more. Singleton classes, case classes, functional-type things, etc. Not sure if this is a good thing or a bad thing, but we'll see.

It also removes a bunch of Java stuff: the ternary operator, break, continue, static methods/variables, "static inner classes", C style for loops, etc. I would say Scala is roughly the same complexity as Java. It's just much of what it adds are either functional in nature or lead to styles of modular composition that are foreign to Java or C++ programmers. This gives the impression that it's more complicated.

> but I find myself still preferring C++ when I need a language with structure

They're very different languages. Until you get a feel for Scala as a functional language it's just going to seem arbitrarily weird.

Besides its low level nature, the one thing that I miss from C++ is template meta-programming. But frankly, I'd much rather have full blown templates a'la Template Haskell or Nemerle than C++'s system.

Rob Britton said...

A very informative comment, thank you.

> It's imperative in the same way that ML is imperative - or functional in the same way that ML is functional.

Interesting. I think I didn't notice this because I approached Scala as an imperative language, but ML as a functional language. I also don't have extensive programming experience in ML.

> Scala's libraries add things like actors, parser combinators, and functional collections. Unfortunately, IO is pretty under-represented in the libraries right now.

Actors are an excellent addition IMO.
It's unfortunate that IO is underrepresented, but as you said it plans to be changed with Scalax. Definitely a good sign.

> It also removes a bunch of Java stuff: the ternary operator, break, continue, static methods/variables, "static inner classes", C style for loops, etc.

I noticed that the ternary operator was gone. Why was it removed? In my opinion it suits functional programming rather well.
Break/continue I can understand, although I do use them on occasion...

> This gives the impression that it's more complicated.

Forgive the ignorance of us Java/C++ programmers (although I rarely write code in either language these days), we aren't comfortable outside our little box ;)

> They're very different languages. Until you get a feel for Scala as a functional language it's just going to seem arbitrarily weird.

I think my problem has been that I've been approaching Scala as an imperative language.

> Besides its low level nature,

Mmmm...low level. I hate to say that I really like being close to the metal, even though it makes programming more difficult sometimes.

> the one thing that I miss from C++ is template meta-programming. But frankly, I'd much rather have full blown templates a'la Template Haskell or Nemerle than C++'s system.

I think that all of C++'s features are implemented better somewhere else. However I find that C++ provides more of a happy medium among a vast amount of features, sort of like a jack-of-all-trades type thing compared to a specialized focus. I do miss using functional closures when programming C++ though...

You've definitely renewed some curiosity in Scala. I will continue in my adventures.

James Iry said...

> I noticed that the ternary operator was gone. Why was it removed? In my opinion it suits functional programming rather well.

Yup - the answer is that, just like with most functional languages, Scala's "if/else" is an expression rather than a statement. So the C++/Java

c = a==b?1:2

would be this in Scala

val c = if(a==b) 1 else 2

But you can still use it imperatively if you want to

var c = _
if (a==b) c = 1 else c = 2

> Break/continue I can understand, although I do use them on occasion...

Yup. Just like C's goto - handy on occasion but problematic in heavy doses. The main reason to get rid of Java's labeled break and continue statements is that the labels should logically get captured by closures and that would be a nightmare. Unlabeled break and continue aren't quite so problematic, but also not as handy. It's a bit of a loss, but not too big a deal.

> I think my problem has been that I've been approaching Scala as an imperative language.

One of Scala's great strengths is that you can "write Java in Scala" (at least semantically if not syntactically).

Unfortunately, it also leads to a wrong impression about what it is. Think about the C/C++ relationship. You CAN write C in C++ (even syntactically) but doing so ignores most of the power of the language. I'm sure you've seen a lot of C++ code that was really just C with a nicer IO library.

Rob Britton said...

> Unlabeled break and continue aren't quite so problematic, but also not as handy.

They are still pretty handy, I use them fairly often in Ruby to keep within the 80-character line limit ;)

> It's a bit of a loss, but not too big a deal.

I've never seen a situation when I've used break/continue where I couldn't have done it another way.

> One of Scala's great strengths is that you can "write Java in Scala" (at least semantically if not syntactically).

I'm not incredibly certain it is a strength ;) however it will help Scala gain popularity. I think the same thing happened with C++ in the late 80's/early 90's. Unfortunately I was a little young then so I can't verify this for certain.

> I'm sure you've seen a lot of C++ code that was really just C with a nicer IO library.

The C++ version of DirectX comes to mind.

Again, your comment is very informative. What do you think is the best way to get Scala "out there"? Besides blogging about it of course.