Showing posts with label scala. Show all posts
Showing posts with label scala. Show all posts

Tuesday, 18 March 2008

Scala syntax change proposal

I came up with a neat idea for changing the syntax for call by name parameters recently (it turned out that it's actually a reversion to an older syntax for it! The new one was there to resolve some problems, but I like the old syntax better so would rather resolve those problems directly). In the discussion of this some problems were pointed out and the feature list sortof spiralled out of control and collided head on with a previous proposal by Andrew Foggin. Here's a summary of the current state of the proposal.

  • Any of the modifiers currently allowed for local variables is allowed as either a function argument or a constructor parameter. i.e val, lazy val, var or def.
  • A parameter marked as def has the same semantics as call by name parameters currently do. It replaces the old syntax (or, rather, the new syntax).
  • A function taking N arguments is equivalent to a function taking a ProductN (modulo compiler optimisations). So given def stuff(val foo, var bar, def ba z) the invocation stuff(x, y, z) is equivalent to the invocation stuff(new Product3{ val _1 = x; var _2 = y; def _3 = z; })
  • In order to take into account the need to make call by name parameters constructor local, and generally improve the behaviour of constructors, we introduce an additional privacy modifier, "local". Conceptually, things marked local are only visible within the constructor. It's basically a stronger form of private, and is the scoping modifier that constructor arguments with no qualifiers currently have. local variables and defs are not visible outside the body of the class. Unlike private members, you may not access the local variables of another member of the same class. Edit: Seth Tisue has pointed out in the comments that you can already do this. The notation for it is private[this]

Monday, 3 March 2008

An introduction to implicit arguments

SBinary and Scalacheck are part of a small set of libraries that make extensive use of implicit arguments in a style very reminiscient of Haskell type classes. I'm hoping this style of programming will get more common in Scala - it's a really useful technique and, in my completely unbiased opinion, both SBinary and Scalacheck are fantastic and you absolutely should use them. :-) But in order to do so you need to really understand how implicit arguments in Scala work.

This post is actually for work, as we're using Scala there and this is a subject which has been confusing one of my colleagues.

As a starting point, in Scala you can declare a method to have multiple argument lists. This isn't a fantastically useful feature, but here's how it works:

scala> def foo(x : Int)(y : Int)
     | = x + y
foo: (Int)(Int)Int

scala> foo(1)(2);
res1: Int = 3

scala> foo(1, 2);
:6: error: wrong number of arguments for method foo: (Int)(Int)Int
       foo(1, 2);
       ^

scala> foo(1)
:6: error: missing arguments for method foo in object $iw;
follow this method with `_' if you want to treat it as a partially applied funct
ion
       foo(1)
       ^

i.e. "exactly the same as a single method parameter list but you have to use a different syntax for calling it". Hurray.

This has one advantage though. You can declare the last parameter list of a function to be implicit. The syntax for this works as follows:

scala> def speakImplicitly (implicit greeting : String) = println(greeting)
speakImplicitly: (implicit String)Unit

scala> speakImplicitly("Goodbye world")
Goodbye world

scala> speakImplicitly
:6: error: no implicit argument matching parameter type String was foud.

scala> implicit val hello = "Hello world"
hello: java.lang.String = Hello world

scala> speakImplicitly
Hello world

So, we can call this as normal but, additionally, we can leave out the implicit argument list and the compiler will look for a value in the enclosing scope which has been marked as implicit. If we try to do that and there is no such value in scope then the compiler will complain.

Matching implicit arguments

Implicits are totally typesafe, and are selected based on the static type of the arguments. Here are some examples to show how things work.

Implicits of the wrong type
scala> def speakImplicitly (implicit greeting : String) = println(greeting)
speakImplicitly: (implicit String)Unit

scala> implicit val aUnit = ();
aUnit: Unit = ()

scala> speakImplicitly
:7: error: no implicit argument matching parameter type String was found.

Only an implicit of type String will be selected for an implicit argument of type String.

Implicits of the wrong static type
scala> def speakImplicitly (implicit greeting : String) = println(greeting)
speakImplicitly: (implicit String)Unit

scala> implicit val hello : Any = "Hello world"
hello: Any = Hello world

scala> speakImplicitly
:7: error: no implicit argument matching parameter type String was found.

Implicit selection happens on the *static* type of variables. It's no use having something of the right dynamic type if the variable isn't typed accordingly.

scala> def speakImplicitly (implicit greeting : String) = println(greeting)
speakImplicitly: (implicit String)Unit

scala> implicit val foo = "foo";
foo: java.lang.String = foo

scala> implicit val bar = "bar";
bar: java.lang.String = bar

scala> speakImplicitly
:9: error: ambiguous implicit values:
 both value bar in object $iw of type => java.lang.String
 and value foo in object $iw of type => java.lang.String
 match expected type String

If there are multiple implicit arguments of the same type, it will fail as it has no way of choosing between them. But...

Implicit arguments of subtypes
scala> def sayThings (implicit args : List[Any]) = args.foreach(println(_))
sayThings: (implicit List[Any])Unit

scala> implicit val nothingNiceToSay : List[Any] = Nil
nothingNiceToSay: List[Any] = List()

scala> sayThings

scala> implicit val hellos : List[String] = List("Hello world");
hellos: List[String] = List(Hello world)

scala> sayThings
Hello world

If you have an implicit argument of a subtype, it will also match as an implicit argument of this type. Moreover, if you have two implicit arguments which match and one is a subtype of the other, the more specific type will match.

Parameterized implicits
scala> def implicitly[T](implicit t : T) = t
implicitly: [T](implicit T)T

scala> implicit val foo = "foo"
foo: java.lang.String = foo

scala> implicit val aUnit = ()
aUnit: Unit = ()

scala> implicitly[String]
res2: String = foo

scala> implicitly[Unit]

Type parameters can quite happily take part in the implicits mechanism.

Defining implicit arguments

So, we know how to use defined implicit arguments now. But how can we define them? We've seen one way:

implicit val foo = "foo";

scala> implicitly[String]
res2: String = foo

If this was all we could do then it wouldn't be that powerful a feature. A nice to have, but ultimately not *that* exciting. Fortunately there are a few more things we can do. For starters, Scala has the uniform access principle, so any (wait, no. That would be too general. We can't have features without special cases. Sigh. Ok, let's say most) things you can do with a val you can do with a def

implicit def foo = "foo"

scala> implicitly[String]
res2: String = foo

This def will be invoked each time we want the implicit. Here's an example to demonstrate this

scala> implicit def aUnit : Unit = println("Hello world")
aUnit: Unit

scala> implicitly[Unit]
Hello world

scala> implicitly[Unit]
Hello world

scala> implicitly[Unit]
Hello world

In general, implicit defs shouldn't have side effects. It can lead to some really counterintuitive behaviour. This is just for demonstration purposes.

Now, the ability to use defs opens up a bunch of possibilities. For example, they can have type parameters:

scala> implicit def emptyList[T] : List[T] = Nil;
emptyList: [T]List[T]

scala> implicitly[List[String]]
res9: List[String] = List(Hello world)
// Oops, we still had an implicit List[String] left over from an earlier example. Note how that was used in preference to the parameterized version. Let's try again.

scala> implicitly[List[Int]]
res10: List[Int] = List()

Moreover, implicit defs used in this way can themselves have implicit parameters. For example:

scala> case class Foo[T](t : T);
defined class Foo

scala> implicit val hello = "Hello"
hello: java.lang.String = Hello

scala> implicit def foo[T](implicit t : T) = Foo[T](t)
foo: [T](T)Foo[T]

scala> implicitly[Foo[String]]
res3: Foo[String] = Foo(Hello)

(Note: I originally tried to write this example with Option. It turns out there's a bug with how covariant types are handled which made it not work)

The basic idea is that anything marked as implicit which you could write as a single identifier (possibly with a type signature to handhold the type inference system) is valid to be passed as an implicit argument.

More reading

This should provide enough to get you started. Your next step should probably be to check out the documentation for Scalacheck and SBinary (the latter of which is... less than stellar at the moment. I'll fix that, I promise. :-)). If you're looking for some slightly more hardcore reading, Generics of a Higher Kind has some interesting examples. Other than that, the best thing to do is play with some code.

Saturday, 1 March 2008

Existential types in Scala

With 2.7 of Scala on the way, people are being exposed to Java wildcards more and more, which translate to Scala existential types. Unfortunately no one seems to understand these (including me at first!) and had previously let them go largely ignored, and now everyone is getting confused.

Here's a brief introduction.

scala> def foo(x : Array[Any]) = println(x.length);
foo: (Array[Any])Unit

scala> foo(Array[String]("foo", "bar", "baz"))
:6: error: type mismatch;
 found   : Array[String]
 required: Array[Any]
       foo(Array[String]("foo", "bar", "baz"))

This doesn't compile, because an Array[String] is not an Array[Any]. You can put 1 into an Array[Any], but not into an Array[String]. Nonetheless, it's completely typesafe - we've only used methods in foo which would work for any Array[T]. How do we fix this?

Here's one way:

scala> def foo[T](x : Array[T]) = println(x.length)
foo: [T](Array[T])Unit

scala>> foo(Array[String]("foo", "bar", "baz"))
3

We've parameterised the method by T in order to make it accept any T. But now we have a superfluous type parameter on our method. This may not seem like a big deal, and it's usually not, but it can add up if you're not careful (and can be particularly annoying when for some reason the type checker is no longer able to infer a single one of your type parameters and you have to supply all of them). It's also not really what we mean - we mean "I want an Array, and I don't care what type of things it contains"

This is exactly what existential types are for.

scala> def foo(x : Array[T] forSome { type T}) = println(x.length)
foo: (Array[T] forSome { type T })Unit

scala> foo(Array[String]("foo", "bar", "baz"))
3

This is quite verbose, I know. There's a shorthand, Array[_], but this has some unfortunate unintuitive behaviour. I'll explain this later.

Sometimes we want to act on a more specific type, but don't care exactly what type it is. For example suppose we wanted this to work on any CharSequence and do something more complicated to each argument. e.g.

scala> def foo(x : Array[T] forSome { type T <: CharSequence}) = x.foreach(y => println(y.length))
foo: (Array[T] forSome { type T <: java.lang.CharSequence })Unit

scala> foo(Array[String]("foo", "bar", "baz"))
3
3
3

The type arguments in an existential type can have upper and lower bounds like normal type declarations. They can't have view bounds, presumably due to technical limitations.

So we've seen how these are used, and that was relatively nonconfusing (I hope!). Let's pin down exactly what these mean.

Suppose we have a type constructor M. In other words, for a type T, M[T] is a type, but M is *not* itself a type. M could be List, Array, Class, etc. M[T] forSome { type T; } is the type of all things for which there is some T such that they are of type M[T]. So an Array[String] is of this type, because we can choose T = String, as is an Array[Int], etc.

If we add bounds, all we do is restrict the range that T can lie in. An Array[String] is not an Array[T] forSome { type T <: Number; } because the only possible choice of T (String) is not a subtype of Number

Now, all you need to do in order to understand a given existential type declaration is to apply this rule rigorously. But this can be hard, especially because precedence matters in subtle ways! I'll walk you through some examples.

T forSome { type T; }

This is the type of all things for which there exists some T such they are T. Wha?

Think about it for a second. It's the type of all things for which there exists a type such that they are of that type. i.e. it's a long winded way of writing the type of all things, Any. This is important, and it often trips people up when they write subtly the wrong thing. Considering the following two types:

Array[T] forSome { type T; }
Array[T forSome { type T; }]

They look almost identical, but they're in fact very different. The first is the type of all arrays, whatever their type parameter. The second is Array[Any]

Let's take another example, because this is the one which seems to come up a lot. We have a Map. We want it to map classes to something. Let's say Strings. What type do we use?

Here. Pick one:

Map[Class[T forSome { type T}], String]
Map[Class[T] forSome { type T}, String]
Map[Class[T], String] forSome { type T}

Which did you pick?

The correct answer is "Map[Class[T] forSome { type T}, String]", or to save you searching for ]s, "the middle one".

Why? Well, the first one is a Map[Class[Any], String]. Class is invariant in its type parameters. So the only Class[Any] is in fact classOf[Any] (this is basically the same as Object.class in Java). So that's not very useful. Similarily, the third one is the supertype of all map types such that there is some T such that they are a Map[Class[T], String]. So again, we've got some fixed class type for keys in the map - it's just that this time we don't know what type it is. The middle one however has keys of type Class[T] forSome { type T }. That is, its keys are classes which are allowed to have any value they want for their type parameter. So this is what we actually wanted.

Now, the final confusing point. As I mentioned, we have this shorthand use of _ for wildcards. So we can write Array[_] to mean Array[T] forSome { type T}. That's nice. So what happens if we try to use this in the above and write Map[Class[_], String]? It turns out, we get "Map[Class[T], String] forSome { type T}". The wildcards always bind to the outermost level of the type expression. This is, unfortunately, almost never what you want in cases where it affects anything. There's been some discussion about changing it. I don't know if it will go anywhere.

Anyway, hopefully this has made some sense of things for you. It's a really confusing subject when you first encounter it, but once you've got it straight in your head it's not too bad. It would be nice if it could be simpler, but I'm not really sure what the best way to do this actually would be.

Saturday, 23 February 2008

Hector's Reminder Service: QT Jambi and Scala

Well, I spent a lot of today putting together the application I mentioned in my recent rant.

The program is called "Hector's Reminder Service". Basically it's a taskbar reminder app. You specify a random lists of messages and their approximate frequency. It gives a little notification message (not a popup window!) on the task bar showing one of those messages about that often. You can configure as many different groups of messages as you like and they'll be scheduled independently.

The code is available here. It's GPLed, mostly because it depends on QT and I couldn't be bothered to figure out the ramifications. Anything I consider reusable will be factored out into a library and released under a more moderate license. I have a few more things to sort out with it (mainly packaging) and will then release a version 0.1 of it.

Currently there's no packaging system set up. If you want to build this you'll need QT Jambi installed - both for the user interface file compiler and for the native libraries. It's currently untested on anything except windows, but now that I've given up on Swing and switched to QT I expect it should by and large work on OSX or any X-windows setup with a compliant toolbar. No doubt there will be problems, but they should be surmountable. Give me a shout if you do want to build it and discover it doesn't work on your platform. I'll do my best to help.

Edit: Actually, unless you're feeling brave you probably don't want to build this. It depends on having Scala 2.7 and jerbil installed as well as the QT Jambi libraries. You can download a prebuilt version from http://hectorreminder.googlecode.com/files/hector.zip , but you'll still need the QT Jambi libraries installed.

Edit 2: I can confirm that Hector does work properly under linux. You need to replace the qtjambi.jar in the lib directory with the one from your jambi install (turns out that's windows specific. Oops). Other than that he works perfectly.

Sunday, 10 February 2008

Easy binary serialization of Scala types

I'm going to be prototyping some stuff in Scala at work in the coming week, and wanted a nice way of marshalling things to/from files and across the network. The BytePickle stuff in scala.io does nothing for me, and Java serialization gives me the screaming heebie jeebies, so this prompted me to get off my ass and do something I've been meaning to do for a while - port something akin to Haskell's Data.Binary to Scala using the encoding of type classes I've previously discussed. Well, it's done - it didn't take very long at all. The port is *extremely* loose - in particular I've just written it for imperative use rather than define custom monads for reading and writing in a pure manner (sorry). The project is hosted on google code at http://code.google.com/p/sbinary/

At its heart it's extremely simple:

trait Binary[T]{
  /**
   * Read a T from the DataInputStream, reading no more data than is neccessary.
   */
  def reads(stream : DataInputStream) :T;

  /**
   * Write a T to the DataOutputStream.
   */
  def writes(t : T)(stream : DataOutputStream) : Unit; 
}

object Operations{
  /**
   * Use an implicit Binary[T] to read type T from the DataInputStream.
   */ 
  def read[T](stream : DataInputStream)(implicit bin : Binary[T]) : T = bin.reads(stream);

  /**
   * Use an implicit Binary[T] to write type T to the DataOutputStream.
   */
  def write[T](t : T)(stream : DataOutputStream)(implicit bin : Binary[T]) : Unit =  
    bin.writes(t)(stream);
}

Err. That's it. Did you want more? :-)

There's more to it than that of course, but most of the rest of the code I've written for this is just helper methods, instances and scalacheck tests.

Out of the box this will serialise tuples of any size (that Scala supports. i.e. of 22 elements or fewer), lists, arrays, immutable maps, options, Strings, all the AnyVal types and any combination thereof. Looking at the code should give you an idea of how to define your own Binary instances.

Using it is very simple. It works by knowing the type of thing you want to read or write from the stream and selecting the appropriate logic based on that type (but, unlike Java serialization, if you give it the wrong type it will attempt to read it as that type anyway and probably do crazy things - this is very explicitly using the type to define a compact encoding and doesn't select it based on dynamic information from the stream). e.g.

  import binary.Operations._;
  import binary.Instances._;
  val foo = read[(Int, Option[String], List[Int])](inStream);
  write(foo._2)(outStream);

The read and write methods on Operations take care of selecting an appropriate implicit instance of Binary and combining them to do the right thing.

Note that binary serialization logic is kept entirely external to the class, so it's almost as easy to define for classes from external libraries as it is for your own.

I'm not doing an official release yet - I want to have a play around with this and see how usable it is. Once I have, I might change the API around to improve it. On the other hand, the code works now and does enough (within its very simple objectives) that it's probably useful. I've written a bunch of scalacheck tests for it and am reasonably confident it gets all the current binary instances right. If you want to use it for something, go right ahead! Report back to me and let me know how it goes.

Edit: By the way, this only works properly on 2.6.1 or higher. There were some problems with the implicit arguments implementation prior to then that prevent the instances from working correctly.

Wednesday, 16 January 2008

Learning Scala

Some questions for people who are learning / have learned Scala: What languages did you know beforehand, and how easy did you find learning Scala in comparison to these? Are there any languages which you found knowing particularly helpful when picking up Scala? An explanation follows: Scala seems to be a relatively hard language to learn for some people, not so much for others. Part of this is its complexity - it really does have a lot of little features - but I'm wondering if more of it might be its approach. It's a language with two major inspirations - object orientation (in the peculiar flavour of it Java practices) and statically typed functional programming, and I'm not sure how easy it is to understand the language unless you understand where it's coming from in this regard. In particular one thing we've observed in #scala from people learning the language is that if you know both Java and Haskell (I presume an ML would work as well?), learning Scala becomes significantly easier. I had almost no trouble picking it up, but I know both. Ricky Clarkson seems to be in a similar boat in terms of Haskell + Java having helped. I presume others are too. On the other hand, people with Java background but not much FP seem to have more trouble and people coming from a predominantly ruby or python background have a harder time yet. (I don't know what happens to people coming from a Haskell with no Java background. I'd expect a similar degree of confusion to the Java with no Haskell background). Some of this is probably in terms of material - a lot of Scala tutorials, etc. out there seem to assume you already know Java. This is probably largely accurate but seems like a mistake in the long-term to me. On the other hand, I'd be really uncomfortable teaching Scala as a first language, so what languages *should* they be learning to prepare the way? Anyone tried learning it on the basis of, say, Ruby + OCaml? So, what do we want people's path into Scala to be? Should we suggest they learn Java first if they don't want a bit of a rough start, or is there a better way?

Wednesday, 9 January 2008

Minor revelation about Scala existential types

So, I've just realised why Scala's existential types are several orders of magnitude more powerful than Java's wildcards.
   def swap(xs : Array[T forSome { type T; }]) = xs(0) = x(1); 
The type is not completely unknown, and is persisted across method invocations, so for a given fixed instance you can make use of that to perform operations that would be impossible with wildcards. In particular the following can't work:
  public void swap(List<?> xs){ 
    xs.set(0, xs.get(1));
  }
This can't work, because Java has no way of determining that the two wildcards in xs.set and xs.get are the same.

Sunday, 6 January 2008

Dereferencing operators

I'm writing a small library for mutable reference cells. This has spawned a heated debate about what to call the dereferencing operator. Possible options for dereferencing foo are: One of the big questions is whether it should be postfix or prefix. If it's postfix, using them as properties becomes much more readable. foo.bar! vs. !(foo.bar). But it also runs into weird precedence issues. On the other hand, the set of characters which can be used in a prefixy manner is really limited and they all seem to have significant meaning. !foo Pros: Historical precedent. It's what ML uses. Cons: Very easy to confuse with negation. Suppose foo is a reference to a boolean. if (!foo) { } is potentially really confusing. foo! Pros: Same as !foo. Less confusing - it's not currently used by anything major. Cons: Retains misleading association with negation, although less easy to write confusing code. foo& Pros: Historical precedent. Looks almost like C (prefix & isn't legal). Cons: Similar confusion to !. & more normally means and. On the other hand, C programmers seem to have gotten used to it. @foo Pros: Nice distinctive character. Easy to get used to. Cons: It isn't legal Scala (this is kinda a big one :-) ). ~foo Pros: Same as @. Legal Scala. :-) Cons: Prefix operator, so doesn't work well with properties. Somewhat non-obvious. foo<> (credit to Bob Jones... err. I mean Jan Kriesten for this one) Pros: Visually distinctive and appealing. Cons: Looks vaguely directional. foo^ (credit to Martin Odersky) Pros: Um. Beats me. Cons: Confusion with xor. Looks weird. foo deref Pros: Fewer weird precedence issues because it's not an operator. Some people seem to like wordy operator names. Cons: Visually distracting, overly verbose. Scatters meaningless words throughout the code. Core operations should have nice symbolic notation. Additional cons: Over my dead body. foo() (credit to Eric Willigers) Pros: Interacts much better with precedence rules than any of the others. You can write foo() == "Bar" whereas you'd have to write (foo!) == "Bar". It seems intuitively obvious what invoking a reference should mean. Cons: I don't really have a good argument against this except that it feels wrong. It looks a little weird when you have a reference to a function. e.g. if you had a Ref[() => Unit] it would be potentially easy to write myRef() and think you'd invoked it, when in fact you'd merely returned a function. Any of the above with an implicit conversion from references to their contents Pros: The mainline case is syntax free. Cons: No no no no no no no. This creates *exactly* the sort of confusion between reference cells and their values that I'm trying to avoid, and opens up the possibility of huge classes of subtle bugs where you passed a reference to an object and meant to pass the object. I initially thought it was a good idea, and it has a strong intuitive appeal to it, but I'm convinced it would be disastrous. A slight conciseness advantage in no way offsets the introduction of perniciously evil bugs. On balance I think foo() is going to win. The precedence issues seem to prohibit the use of any sort of postfix operator. This seems to leave ~foo as the only good alternative, and I think it's less obviously meaningful and the prefix nature would annoy the properties people.

Thursday, 3 January 2008

Why not Scala?

I thought I'd follow up on my previous post on why one would want to use Scala with one on why you wouldn't. I'm definitely planning to continue using it, but it would be dishonest of me to pretend it was a perfect language. I'm not going to cover the usual ones - weak tool support, difficulty of hiring Scala programmers, etc. These are pretty standard and will be true in most 'esoteric' languages you care to name. They're certainly important, but not the point of this post. I'm just going to focus on language (and implementation) issues.

You're looking for a functional language

Scala is not a functional programming language. It has pretensions of being so, and it has adequate support for functional programming, but it only goes so far. It's got better support for functional programming than C#, Ruby, etc. but if you compare its functional aspects to ML, Haskell, OCaml, etc. you'll find it sadly lacking. Problems include:
  • Its pattern matching is really rather cumbersome.
  • An annoying distinction between methods and functions. Scala's first class functions are really no more than a small amount of syntactic sugar around its objects. Because Scala's scoping is sane this isn't particularly an issue, but it occasionally shows up.
  • The handling of multiple arguments is annoying. It doesn't have the pleasant feature of Haskell or ML that every function has a single argument (multiple arguments are encoded as either tuples or via currying). Admittedly this isn't a prerequisite of a functional language - e.g. Scheme doesn't do it - but it's a very big deal in terms of typing and adds a nice consistency to the language. I'm not aware of any statically typed functional languages which *don't* do this (although the emphasis between tupling and currying varies from language to language).
  • Almost no tail call elimination worth mentioning. A very small subset of tail calls (basically self tail calls - the ones you can obviously turn into loops) are eliminated. This is more the JVM's fault than Scala's, but Martin Odersky himself has shown that you can do better (although admittedly it comes with a performance hit).
  • The type inference is embarrassingly weak. e.g. recursive methods won't have their return type inferred. Even what type inference is there is less than reliable.

Compiler stability

The compiler is buggy. It's not as buggy as I sometimes get the impression it is - I've definitely claimed a few things to be bugs which turned out to be me misunderstanding features - but it's buggy enough that you'll definitely run into issues. They're rarely blockers (although sometimes they are. Jan Kristen has run into a few with his recent experiments with wicket + scala), but more importantly the bugginess means you really can't trust the compiler as much as you'd like to. When something goes wrong it's not always certain whether it's your fault or the compiler's. This is a big deal when one of the selling points is supposed to be a type system which helps you catch a wide class of errors.

Language consistency

The language has a lot of edge cases. These can be really difficult to wrap your head around, and can be really annoying to remember. Let's take an example. Variables. Simple, eh? Well, no. A variable (local or field) can be a function (or constructor) parameter, a val, or a var. A val is a definition - it can't be assigned to after the definition is made. A var is a normal mutable variable like in Java. A function parameter is almost like a val, except for the parts where it isn't. Additionally, a function parameter can also be a var or a val. But it doesn't have to be. Variables can be call by value (normal), call by name (the expression is evaluated each time you reference its value) or lazy (the expression is evaluated the first time you need its value and never again). But only vals can be lazy. And function parameters can't be lazy, even if they're also vals (I don't understand this one. It seems obviously stupid to me). Meanwhile, only function parameters can be call by name - you can't assign them to vars or vals (a no argument def is the equivalent of a call by name val). Clear as mud, eh? Now, granted I wrote the above to make it sound deliberately confusing (it's probably owed a blog post later to make it seem deceptively simple), but it's a fairly accurate representation of the state of affairs. Here's another one (it's related to the arguments issue). Consider the following snippet of code:
def foo = "Hello world";
println(foo());

def bar() = "Goodbye world";
println(bar);
Pop quiz: Does this code compile? If not, which bit breaks? No cheating and running it through the compiler! Answer: No, it doesn't. Because foo was defined without an argument list, it can't be invoked as foo(). However, despite bar being defined with an (empty) argument list we can invoke it without one. I could keep going, but I won't. The short of it is that there are a lot of these little annoying edge cases. It seems to give beginners to the language a lot of grief.

Too much sugar

Scala has a lot of syntactic sugar. Too much in my opinion. There's the apply/update sugar, unary operators by prefixing with unary_, general overloaded assignment (which, as I discovered when testing, only works in the presence of an associated def to go with it. Another edge case). Operators ending in : are left associative. Constructors are infixed in pattern matching case classes but not in application. etc. It's hard to keep track of it all, and most of it is annoyingly superfluous.

Lack of libraries

Yes, yes, I know. It has all of the Java libraries to play with. And this is great. Except... well, they're Java libraries. They're designed with a Java mindset, and they can't take advantage of Scala's advanced features. Implicit conversions, and a number other tricks, are quite useful for making an API more palatable, but there's a strong danger that what you end up with isn't much more than Java with funny syntax. Much more than that requires a reasonable amount of porting work to get a good API for your use. All in all, I find these add up to just a bunch of annoyances. It's still my preferred language for the JVM, but depending on how you wait your priorities they might be more significant for you. Even for me I occasionally find myself getting *very* irritated with some of these.

Variance of type parameters in Scala

This is just a quick introduction to one of the features of Scala's generics. I realised earlier on IRC that they're probably quite unfamiliar looking to people new to the language, so thought I'd do a quick writeup.

What does the following mean?

  trait Function1[-T1, +R]

It's saying that the trait Function1 is contravariant in the parameter T1 and covariant in the parameter R.

Err. Eek. Scary words!

Lets try that again.

A Function1[Any, T] is safe to use as a Function1[String, T]. If I can apply f to anything I can certainly apply it to a String. This is contravariance. Similarly, a Function1[T, String] can be quite happily treated as a Function1[String, Any] - if it returns a String, it certainly returns an Any.

So, Foo[+T] means that if S <: T then Foo[S] <: Foo[T]. Foo[-T] means that if S <: T then Foo[T] <: Foo[S] (note the swapped the direction). The default Foo[T], called invariant, is that Foo[S] is not a subtype of Foo[T] unless S == T.

Examples of this sort of behaviour abound. Covariance is more common than contravariance, because immutable collections are almost always covariant in their type parameters. An immutable.List[String] can equally well be treated as an immutable.List[Any] - all the operations are concerned with what values you can get out of the list, so can easily be widened to some supertype.

However, a mutable.List is *not* covariant in its type parameter. You might be familiar with the problems that result from treating it as such from Java. Suppose I have a mutable.List[String], upcast it to a mutable.List[Any] and now do myList += 3. I've now added an integer to a list of Strings. Oops! For this reason, mutable objects tend to be invariant in their type parameters.

So, we have three types of type parameter: Covariant, contravariant, invariant. All three crop up and are quite useful.

But there are safe ways to treat mutable objects invariable. Suppose I want someone to pass me an array of Foos, and I have no intention of mutating it. It's perfectly safe for them to pass me an array of Bars where Bar extends Foo. Can I do this?

Well, this can indeed be done. We could start by doing this:

  def doStuff[T <: Foo](arg : Array[T]) = stuff;

So we introduce a type parameter for the array. Because T will be inferred in most cases, this isn't too painful to use, but it can quickly cause the number of type parameters to explode (and you don't seem to be able to let some type parameters be inferred and some be explicitly provided). Further, we only care about the type parameter in one place. So, let's move it there.

  def doStuff(arg : Array[T forSome { type T <: Foo }]) = stuff;
This uses Scala's existential types to specify that there's an unknown type for which this holds true. This is effectively equivalent to the previous code, but narrows the scope of the type parameter. The equivalent using Java style wildcards would be:
  def doStuff(arg : Array[? <: Foo ]) = stuff;

But this isn't legal Scala. This is unfortunately a case of Scala being more verbose than the Java equivalent. However, it's not all bad - because of the explicitly named type inside the forSome, you can express more complicated type relationships than wildcards allow for. For example the following:

  def doStuff(arg : Array[T forSome { type T <: Comparable[T]}]) = stuff;

And that's about it for variance in Scala. Hope you found it useful.

Thursday, 20 December 2007

Type classes in Scala

Some backstory on this post: I got about halfway through writing it before realising that in fact it didn't work because of a missing feature. I sent an email to the mailing list about this feature and after some discussion it was concluded that in fact this missing feature was a failure to meet the specification and that it had been fixed in 2.6.1. There's still one thing lacking, but more on that later. The post now resumes. I mentioned in a recent post that Scala could emulate Haskell type classes with its implicit defs and first class modules. In actual fact, the situation is much happier than that. Implicit defs + first class modules give you significantly more than Haskell type classes (although with a tiny loss of type safety). At least, much more than Haskell 98. In particular, multiparameter type classes and associated types come for free. You also gain a number of other advantages, such as type class instantiation scopes lexically, so you can redefine type classes locally. So, how does all this work? I'll begin with a general introduction to this style of programming with no real reference to Haskell, and then I'll tie this back in to encoding Haskell type classes at the end of it. Here's a class that's familiar to anyone who has written non-trivial Java:
trait Comparator[T]{
  def compare(x : T, y : T) : Int; 
}

trait Comparable[T]{
  def compareTo(t : T);
}
Now, let's define the following method:
def sort[T](array : Array[T])(implicit cmp : Comparator[T]) = stuff
So our sort method can either have a comparator passed to it explicitly or it will pull one from the surrounding environment. For example we could do:
object SortArgs{
  implicit val alphabetical = new Comparator[String]{
     def compare(x : String, y : String) = x.compareTo(y);
  }

  def main(args : Array[String]){
     println(sort(args));
  }
}
Will pick up the alphabetical instance. It would be nice if we could also have defined the more general version:
object SortArgs{
  implicit def naturalOrder[T <: Comparable] = new Comparator[T]{
     def compare(x : T, y : T) = x.compareTo(y);
  }

  def main(args : Array[String]){
     println(sort(args));
  }
}
But this doesn't seem to work. :-/ Hopefully this will be fixed - it seems like wrong behaviour. Matt Hellige came up with the following workaround, but it's not very nice:
object Sorting{
    trait Comparator[T]{
        def compare(x : T, y : T) : Int;
    }

    def sort[T](arr : Array[T])()(implicit cmp : () => Comparator[T]) = null;
    implicit def naturalOrder[T <: Comparable]() : Comparator[T] = null;
    implicit def lexicographical[T]() (implicit cmp : () => Comparator[T]) :
        Comparator[List[T]] = null;

    def main(args : Array[String]){
        sort(args);
        sort(args.map(List(_)))
        sort(args.map(List(_)).map(List(_)))
    }
}
Moreover I haven't the faintest notion of why it works. :-) However we can also chain implicit defs:
   implicit def lexicographicalOrder[T] (implicit cmp : Comparator[T]) : Comparator[List[T]] = stuff;
So now the following code *does* work:
  def main(args : Array[String]){
    sort(args);
    sort(args.map(List(_)))
    sort(args.map(List(_)).map(List(_)))
  }
}
An amazingly nice feature of this which some encodings of type classes miss is that you don't need an instance of a type to select on that type. Take for example the following:
object BinaryDemo{
  import java.io._;
  trait Binary[T]{
    def put(t : T, stream : OutputStream);
    def get(stream : InputStream) : T;
  }

  implicit val utf8 : Binary[String] = null;
  implicit def binaryOption[T] (implicit bin : Binary[T]) : Binary[Option[T]] = null;

  val myStream : InputStream = null;

  def readText(implicit bin : Binary[Option[String]]) : Option[String] = bin.get(myStream);

  readText match{
    case None => println("I found nothing. :(");
    case Some(x) => println("I found" + x);
  }
}
Unfortunately this example betrays a weakness in our encoding. I can't just randomly call "get" like in Haskell's Data.Binary - because I need to invoke it on an instance of Binary[T] I need to ensure at the method level that one is available. There doesn't appear to be a good way of getting access to implicits from the enclosing scope directly. However, here's a silly hack:
   def fromScope[T] (implicit t : T) = t; 
And we get:
  fromScope[Binary[Option[String]].get(myStream) match{
    case None => println("I found nothing. :(");
    case Some(x) => println("I found" + x);
  }
}
This works just as well with multiple type parameters. For example, if we wanted to port Java's AtomicArray classes without wrapping everything (although admittedly wrapping everything would be more idiomatic Scala) we could do the following:

object ArrayDemo{
  import java.util.concurrent.atomic._;
  trait AtomicArray[S, T]{
    def get(s : S, i : Int) : T;
    def set(s : S, i : Int, t : T);
    def compareAndSet(s : S, i : Int, expected : T, update : T);
  }

 implicit val long = new AtomicArray[AtomicLongArray, Long]{
    def get(s : AtomicLongArray, i : Int) = s.get(i);
    def set(s : AtomicLongArray, i : Int, t : Long) = s.set(i, t);
    def compareAndSet(s : AtomicLongArray, i : Int, expected : Long, update : Long) = s.compareAndSet(i, expected, update);
  }
}
So, that's multi-parameter type classes. But one thing you'll notice about the above encoding is that it's a bloody nuisance to invoke - you need to know the type of the array class you're using, which is annoying. Far better would be if the trait took care of that. In Haskell terms this would be an associated type. No problem.
object ArrayDemo{
  import java.util.concurrent.atomic._;
  trait AtomicArray[T]{
    type S;
    def get(s : S, i : Int) : T;
    def set(s : S, i : Int, t : T);
    def compareAndSet(s : S, i : Int, expected : T, update : T);
  }

 implicit val long = new AtomicArray[Long]{
    type S = AtomicLongArray;
    def get(s : AtomicLongArray, i : Int) = s.get(i);
    def set(s : AtomicLongArray, i : Int, t : Long) = s.set(i, t);
    def compareAndSet(s : AtomicLongArray, i : Int, expected : Long, update : Long) = s.compareAndSet(i, expected, update);
  }
}
Scala's classes can have abstract types. So we just encode associated types as those. So, to recap on our encoding:
  class Foo a where
     bar :: a
     baz :: a -> a

becomes
  trait Foo[A]{
     def bar : A;
     def baz(a : A) : A;
  }

  instance Foo Bar where
  stuff

becomes

  implicit Foo[Bar] bar = new Foo[A]{
    stuff
  }


  instance (Foo a) => Foo [a]

becomes

  implicit def[T] (implicit foo : Foo[A]) : Foo[List[A]];

And for invoking:

  foo = bar

becomes

  val yuck = fromScope[Foo[A]].bar 
So it's a more verbose encoding, but not a terrible one. And it has some abstraction advantages too. For example:
   sortBy :: (a -> a -> Ord) -> [a] -> [a]
   sortBy = stuff;

   sort :: (Ord a) => [a] -> [a]

becomes

   def sort[A](xs : List[A])(implicit cmp : Comparator[A]);
Because our type classes are a form of implicit object passing, we can also use them with *explicit* object passing. Thus we can redefine behaviour much more nicely to behave equally well with an ordered type and explicitly provided comparison functions. This has disadvantages too - you need to be more careful to ensure that you can't accidentally use two instances of the type class. This isn't a major burden though. The general solution is that when you have something which needs to maintain type class consistency between invocations you pass it an instance at construction type. Take for example Haskell's Data.Set. In Haskell getting a new Set (Set.empty) works for any type but almost all the functions for building sets have a constraint that the type belongs to Ord. In Scala you would require an Ord instance to be passed for Set construction but after that would not need one (analagous to Java's TreeSet providing a constructor that takes a Comparator). One thing I haven't covered is type classes which abstract over type constructors rather than types. The reason I haven't covered them is that I've yet to peek into that corner of Scala's type system. However, I assume they work as Tony Morris has done some stuff with monads in Scala. Also, see this paper (which I've not read yet)

Saturday, 15 December 2007

No, seriously, why Scala?

Recently an article called Why Scala? was posted on reddit. It's an ok introduction to the language, but the very fair observation was made that it's much more of a "What is Scala?" than a "Why Scala?". I thought I'd share my thoughts on the subject. Mainly because I like hearing (reading) myself talk (write). :-) Quick background: I initially learned to program in standard ML while at university (self taught, mostly, with the help of some friends doing computer science. I was doing maths). On graduating I then switched tracks entirely and started doing Java web development in a small software firm in London (I've since switched again, but I'm still doing Java professionally). I've also dabbled and read a lot with computer science and programming languages in my spare time since then, filling in the gaps that not having done any real computer science at university left me. My train of thought on the language switch from ML to Java was basically: a) Wow, this is different. b) Ugh. Where are my higher order functions? c) Where are all these random exceptions coming from?? I've compiled the code successfully, isn't it supposed to work now? d) Hmm. But there's some useful stuff here too. Scala's a nice way to scratch both itches, and adds some very interesting features and functionality of its own. It's not my favourite language (I don't really have one. All languages suck. It's just that some of them suck less in interesting ways), but it has a lot I like. Here's a brain dump of some of it.

Things I like:

Object oriented programming
I know, it's so entrenched it's past even bothering with its buzzword status. But object oriented programming has a lot of advantages for medium to large scale composition. It has some disadvantages, and frankly sucks at small scale composition of functionality (which is where functional programming shines), but it allows for some very nice pluggability.
Module oriented programming
ML has higher order modules. I never really used them much when I was programming it more often (mostly because I was only writing enough code to do some simple maths projects. I never wrote anything large scale), but having looked into them in more details since they're really powerful. They're essentially a different take on the composition that object orientation provides. Where object orientation resolves everything dynamically, ML's higher order modules resolve everything statically. This introduces some limitations in flexibility but makes up for them in power and type safety - they provide a much more flexible and interesting abstraction over a type than mere subclassing and interfaces can. Scala has both. Further, it has both and lo and behold they are the same thing. Objects are modules, and can declare their own types (note: This is much more than just declaring an inner class in Java is), imported, etc. Modules are objects and can be instantiated at runtime, extended, etc. You lose a bit of the static guarantees that ML modules but you gain a lot of flexibility from both sides.
Static Typing
I've written too much Java to not like static typing. Wait, I know that sounds like a non sequitur, but read on. I've written too much Java and seen flagrantly stupid and really subtle runtime errors that should never have made it past the compiler coming out of it to not like static typing. NullPointerException, ClassCastException, argh. If you've written enough code in a language like ML, OCaml or Haskell you will know that the compiler is your friend. And, like all good friends, it will yell at you if you do something stupid and then help you pick up the pieces. Scala doesn't quite manage that. If you write code in just the right way you can achieve that level of guarantee (and in some cases, more. But that tends to be the result of abuse of the type system by deranged maniacs), but the combination of subtyping and some Java interoperability decisions mean that it's not quite as good. It's not bad though. So: I like object oriented programming, I like static typing. It logically follows that I must like statically typed object oriented languages, right? Well, in principle, yes. But Scala is the first one I've met with a type system that didn't suck. Scala's traits (a sort of mixin) are so much better to work with than interfaces, the generics work properly, provide variance annotations, etc. A reasonable subset of the types are inferred. Compared to the type systems of Java, C# and C++ it's a dream (it's not as nice as the type systems of the statically typed functional languages I know of. Subtyping seems to cause issues, with a lot of research still needed to make it work well, and Scala seems to have largely ignored what prior work there was Hindley-Milner style type systems with subtyping)
Functional programming
You've all been dreading this section. "Oh no. Now he's going to enthuse about how marvelous functional programming is and how it's going to cure cancer". Nope. Can't be bothered. Functional programming is nice. If you don't believe that, I'm not going to try to convince you of it. Scala's support for functional programming is ok. It has some warts, but it also has some nice points, and it generally works well and isn't too verbose. I'm not going to get any more excited about its presence than I am about the fact that my bike has wheels (but I'd be pretty pissed off if my bike didn't have wheels). Higher order functions, pattern matching, etc. It's all there. It works. Moving on swiftly...
Implicits
Scala offers a bag of features under the keyword 'implicit'. This is one of those things that makes you go "Oh, that's cute" when you first see it and then go "Wow, that's powerful" six months later. Essentially implicits give you statically guaranteed and provided dynamic scoping. You say "I need a Foo. I don't care where it comes from", the compiler says "Here you go" or "Sorry, no Foos today". These can be objects, implicit conversions between types (You know the way Ints get implicitly converted to longs, double, etc in Java? Scala does that too, but it's all programmer definable. They're just library functions in scala.Predefined). If you remember what I said about Scala objects being modules and you've read this paper a little light might just have gone on in your brain. If you haven't read it and don't want to, here's the summary version: Implicit function arguments + first class modules gives you something that looks and quacks very much like Haskell type classes (yes, I know this isn't actually what the paper says, but it follows from it). Mmm. These are the big things to like about Scala. Here are a few little things:
  • Sane constructor/class semantics. If you've written a lot of Java there's a good chance you hate its constructor system. Scala's is much nicer.
  • Expression oriented code. Everything is an expression. You can form compound expressions trivially - { val foo = bar(); baz(foo, foo); } is an expression which evaluates to baz(foo, foo).
  • Sanely uniform scope. Pretty much anything you can do inside a method you can do inside an object and vice versa. Things are for the most part lexically scoped in the right way.
  • The primitive/object divide is much less irritating. Primitives get a few special treatments at the language level, but mostly they're just objects. When things should compile to use primitives, they do. When the primitives need to be boxed, they will be. It's almost entirely transparent.
  • Performance. Scala generates very good (well. 'good'. Java-like) bytecode, which means it gets to take advantage of most of the optimizations the JVM is willing to throw its way. Further it puts a reasonable amount of its own work into performing optimisations on the bytecode, etc so you get those nice juicy abstractions without much overhead. There's essentiall y no performance penalty for choosing Scala over Java
etc. Scala's far from perfect. It has some syntactic weirdnesses, a few issues carried over from Java, a moderately buggy compiler and a host of little features and edge cases that are really hard to keep in your head. However, I find that these issues don't actually do more than annoy you from time to time. The core language is powerful and very useful for just sitting down and writing good code in.

Wednesday, 12 December 2007

Open sourced range types

I've expanded on the range types a little bit and created an open source project for them. In particular they now support subranges in a typesafe way.

Tuesday, 11 December 2007

Statically checked range types in Scala

I was showing off some Scala features earlier (specifically "Oh, hey, look. With proper singleton support + implicit arguments you can completely remove the need for a dependency injection container while losing none of the advantages". More on that later...) and got to discussing the language with Craig, a coworker of mine (well, specifically our CTO. I work at a cool company. :-) ). He asked me if Scala supported range types, to which my answer was something along the lines of "Well, no. But it should be possible to add as a library. Hmm. Might be hard to get it statically enforced though". Turns out it's not. Here's some code: http://snippets.dzone.com/posts/show/4876 How do we use this?
scala> import ranges.Range;
import ranges.Range

scala> val myRange = new Range(0, 10);
myRange: ranges.Range = ranges.Range@10ae3fb

scala> val myRange2 = new Range(0, 20);
myRange2: ranges.Range = ranges.Range@c7014c

scala> val array = new myRange.CheckedArray[String]
array: myRange.CheckedArray[String] = ranges.Range$CheckedArray@280bca

scala> myRange.indices.foreach(x => array(x) = x.toString)

scala> array.mkString
res6: String = Index(0)Index(1)Index(2)Index(3)Index(4)Index(5)Index(6)Index(7)Index(8)Index(9)

scala> array(myRange.minIndex);
res8: String = Index(0)

scala> array(myRange.maxIndex);
res9: String = Index(9)

scala> array(myRange2.minIndex);
:8: error: type mismatch;
 found   : myRange2.Index
 required: myRange.Index
  val res10 = array(myRange2.minIndex);
                            ^

scala> array(myRange.minIndex.mid(myRange.maxIndex));
res11: String = Index(4)

scala> array(myRange.minIndex + myRange.maxIndex);
:8: error: type mismatch;
 found   : myRange.Index
 required: String
  val res13 = array(myRange.minIndex + myRange.maxIndex);
                                              ^

scala> import myRange._;
import myRange._

scala> array(myRange.minIndex + myRange.maxIndex);
:11: error: type mismatch;
 found   : Int
 required: myRange.Index
  val res14 = array(myRange.minIndex + myRange.maxIndex);
                                     ^

scala> array(minIndex + maxIndex);
:11: error: type mismatch;
 found   : Int
 required: myRange.Index
  val res15 = array(minIndex + maxIndex);
                             ^
CheckedArrays (and similarly ArraySlices) are scoped to a particular range object. You can only access them with indices from that same object. You can get Index objects by getting the minimum, the maximum, combining them with various operators, iterating over them or converting from an Integer (at which point it will either min/max it into bounds or throw an IndexOutOfBoundsException if the integer is out of bounds, depending on which method you call). If you import the range (I'm thinking of separating that out into a separate object for convenience with working with multiple ranges) you'll get an implicit convertion from indices to integers (*not* the other way around). Currently nonexistent: Support for subranges, or working with multiple ranges (Update: See below). I think I know how to fix these in a niceish way. Always going to be nonexistent: Can't statically verify that two ranges are equal. This isn't possible in principle, but even simple cases like knowing that new Range(0, 10) and new Range(0, 10) are equal types isn't doable. I don't think this is avoidable without special logic in the compiler or significantly more static resolution of objects than Scala is ever likely to have (e.g. I think we could do this using ML functors and sharing constraints, but it's been so long since I've looked at those that I'm not really sure). Update: Working with multiple ranges is always going to suck without language changes. There's not enough sharing of values at compile time to express what it needs to. Subranges will probably still work though. Update 2: It's been observed that if you don't know Scala then it's non-obvious how this code works. Unlike Java, inner classes of different instances in Scala are actually different types. So given
val range1 = new Range(0, 10);
val range2 = new Range(0, 10);
range1.Index and range2.Index are different types, and may not be freely converted between. So this code works by having Range enforce that its Index elements are in bounds, and the compiler enforces that you can't mix Index elements from different ranges.

Friday, 2 November 2007

Dependency injection in Scala

I (and some others in #scala) have been wondering recently about the state of play for dependency injection in Scala. This is mostly just a brain dump of a few thoughts and a request for feedback. If anyone has any good ideas, please share! As I see it, most of the Java dependency injection frameworks should work fine for Scala. Guice won't because of generics issues, and similarly the generics support from other frameworks (e.g. Spring's type collections) won't though, so you lose a great deal of type safety. You're back to an almost Java-like level of type safety in fact. :) Also these don't take advantage of many of Scala's great features (higher order functions and a more advanced object system in particular), so the whole thing seems rather unsatisfactory. I wondered briefly about a system based on abstract method injection using traits, but I couldn't make it work in a satisfactory manner. The fact that you'd expose dependencies as defs was also unsatisfactory because it means that the compiler doesn't know that they're stable so you can't e.g. import them. There was some discussion in #scala last night about how "dependency injection is useless if you have higher order functions". This seems like nonsense to me. A well designed scala program may have less need for DI because of the presence of higher order functions but the basic need for composing of modules (that's what dependency injection frameworks really are after all - a module composition DSL) is still there, for more or less the same reason why Scala has objects as well as functions. It's not entirely clear to me how DI should work in Scala, both from an API and an implementation point of view. Something Guice-like might be a good starting point (but only a starting point! Porting Guice verbatim to Scala would almost certainly be a bad idea), but it's not clear to me how one would even implement it in Scala. Part of the problem is that Scala lacks a satisfactory metaprogramming facility. It can use Java's reflection, but the scala.reflect packages seem sadly meager. (There do seem to be a bunch of interesting sounding classes in there, but there appears to be no documentation or evidence of prior usage, so I can't figure out what on earth they're for).

Sunday, 14 October 2007

Turn your toString methods inside out

All examples in this post will be written in a pseudo-dialect of Scala. Hopefully they should be easy to translate into your favourite programming language (or Java). I also haven't bothered to compile any of them as they're mostly not entirely valid. Feel free to point out errors. Consider the following code:
class List[T]{
  // list implementation

  override def toString : String = {
    val it = this.elements;
    var result = "[";

    while(it hasNext){
      result = result + (it next);
      if (it hasNext) result = result + ", ";
    }
    result + "]"
  }
}
What's wrong with it? Well, as you presumably know, concatenating two strings of length m and n is an O(m + n) operation (In Haskell or ML it would be an O(m) operation, so this can be made more efficient, but the basic point will still remain). This means we've accidentally made an O(n^2) toString algorithm. Oops. So, the traditional response is:
class List[T]{
  import java.lang.StringBuilder;
  // list implementation

  override def toString : String = {
    val it = this.elements;
    var result = new StringBuilder();

    while(it hasNext){
      result.append(it next);
      if (it hasNext) result.append(", ");
    }
    result.append("]").toString;
  }
}
Great! We've removed all those expensive string concatenations. Now, what happens if we call toString on a List[List[String]]? Umm... Now, consider the following code snippet:
  println(myReallyLongList);
Let's unpack what's going on in it.
  val it = myReallyLongList.elements;
  var result = new StringBuilder();

  while(it hasNext){
    result.append(it next);
    if (it hasNext) result.append(", ");
  }
  println(result.append("]").toString);
So, we've created a big intermediate string via a StringBuilder, then printed it, discarding the string after that. Right? Wouldn't it be great if we'd written the following code instead?
  val it = myReallyLongList.elements;

  while(it hasNext){
    print(it next);
    if (it hasNext) print(", ");
  }
  println("]");
No intermediate structures created at all. And note that the code used to print is almost exactly the same as the code used to append to the StringBuilder. Conveniently there's a useful little interface in java.lang which people tend to ignore. If not, we'd have had to write wrappers. In particular this is a superclass of Writer, PrintStream, StringBuilder and StringBuffer. So, let's rewrite the above code:
class List[T]{
  import java.lang.StringBuilder;
  // list implementation

  def appendTo(ap : Appendable){
    val it = this.elements;

    while(it hasNext){
      ap.append(... // err. What do we do here?
We could just do ap.append(it next toString). But that doesn't solve the first problem - when we nest these things we're creating a lot of intermediate strings and then immediately throwing them away, not to mention having once again introduced a hidden O(n^2) factor. Sadness. :( Let's do the following:
  trait Append{
    def appendTo(ap : Appendable) : Appendable;

    override def toString = appendTo(new java.lang.StringBuilder()) toString;    
  }

  object Appending{
    def append(any : AnyRef, ap : Appendable){
      if (any.isInstanceOf[Append]) any.asInstanceOf[Append].appendTo(ap);
      else ap.append(any toString)
    }
  }
Now we can write it as:
class List[T] extends Append{
  import Appending._;
  import java.lang.StringBuilder;
  // list implementation

  def appendTo(ap : Appendable) = {
    val it = this.elements;
    while(it hasNext){
      append(it next, ap);
      if (it hasNext) ap append(", ");
    }
    ap.append("]");
  }
}
Now, no matter how deeply we nest things, we'll get things printed in a manner with completely consistent performance - no hidden gotchas. There are also other benefits to structuring things this way. If you make everything work based on an API that looks like this you'll tend to write things which work by injecting filters in reading and writing code. And, hey, suddenly all your code works completely transparently when you discover that you need to work with things that are e.g. read off the network, backed by something on the file system, etc. and really need a streaming version of the library. Also note that I'm not saying "Strings are bad". There are a lot of cases where what you need really is a persistently available string. Then, by all means, use toString! But even then this is helpful, as your toString code will work a lot better and more consistently than it might otherwise have done.

Wednesday, 26 September 2007

I Aten't Dead

Surgeon General's Warning: This post contains an excess of hyperlinks. There is anecdotal evidence that excessive linking may be hazardous to your health. I'm still here. :-) I've just been busy with my new job at Trampoline Systems and non-code things. On the computer front, I've been learning (a bit) about spatial data structures and graph algorithms, mostly for work related reasons although also for personal interest. Tinkering with Haskell continues apace - I've been finding that it's a very good language for thinking in, even if I don't write anything big in it. The Lazy Strings project may look like it died, but fear not! It continues. Ok, you probably didn't care either way, but still it continues. I've decided that a) Life is too short to write it in Java and that b) I should just pick an implementation and stick to it. Consequently I've moved to Scala, and have the basics of an implementation based on a finger tree, rather than the traditional balanced binary tree used in a rope. Why a finger tree? Well, umm. Because. :-) Finger trees have nice performance characteristics, are easy to implement, and seem well suited to the task. The version I'm using is very heavily specialised to the task at hand, and measures a number of things up front (currently just length and hash code) to improve performance and allow for various nice optimisations. The main thing to note is that I've been using scalacheck to test properties of the string. It's been a great help. I've not found it that useful for actually tracking down the specifics of the bugs - its error reporting isn't that great - but it's been very useful for showing that they exist and providing enough of a general area that I can track them down myself. The fact that Scala has a REPL has been very useful in doing enough experimentation to pin it down. The utility of these will come to no surprise to those functional programmers reading my blog. :-) Scalacheck isn't quite as nice as Quickcheck and the Scala REPL isn't as nice as most of the ML ones (it's better than ghci though), but they're both good enough, and it's nice having these in Scala. Scala itself I continue to have mixed feelings about. It's a little too Java like. I very much like what it's done with the object system (first class modules. Yay!), and about half of what it's done with the type system, but the whole effect still feels kludgy to me. It's definitely infinitely better than Java though, and doesn't fall much short of being as pleasant as an ML (it's better in some ways, worse in others).

Tuesday, 4 September 2007

Tail call optimisation in Scala

This is just a quick note. I couldn't seem to find any good information on what sorts of tail call optimisations were performed by Scala so I ran a few quick tests. Disappointingly, the answer seems to be not much. A simple tail recursion was turned into a loop, but the following code got no love: object Main extends Application{ def foo (x : Int){ if (x == Integer.MAX_VALUE) Console.println("Hello world!"); else bar(x + 1); } def bar (x : Int){ if (x == Integer.MAX_VALUE) Console.println("Hello world!"); else foo(x + 1); } foo(0); } This isn't really surprising, although it's a bit sad. Eliminating general tail calls seems to be quite hard without just converting everything into CPS and making everything work that way (at least so I'm lead to believe. My expertise on the subject is basically nonexistent), which is probably not a great idea on the JVM. Curiously, if you enabled optimisations with -XO, foo was inlined into bar but the resulting tail recursion was not eliminated. That's probably a bug. Update: It's been pointed out to me that I've gotten myself completely confused on the relationship between continuations and tail call elimination. Please ignore any mumbling to that effect. :-) The issue is apparently that TCO is easy when compiling to assembly and hard when compiling to something like JVM byte code which is higher level and doesn't already support it.