Archive for January, 2008
Functional programming for the object oriented
IBM has now joined the hype behind Scala with a series of articles by Ted Neward (to be fair, he’s been around Scala for a while now).
Java programming, and object-orientation, was the first love for many programmers, and we treat it with the same respect and outright adoration I gave to Bindi. Some developers will tell you that Java programming rescued them from the hellfire-and-brimstone pits of memory-management and C++. Others will say that Java programming elevated them out of the depths of procedural despair. There are even developers for whom object-oriented programming in Java code simply is “the way we’ve always done things.” (And hey, if it worked for my daddy, and his daddy before him!)
Time ultimately overcomes all first loves, however, and there comes a time to move on. The feelings have changed and the actors in the story have matured (and hopefully learned a few new jokes). But more importantly, the world around us has changed. Many Java developers are realizing that much as we love Java programming, it’s time to catch up to the new opportunities in our development landscape and see what we can make of them.
Source: The busy Java developer’s guide to Scala: Functional programming for the object oriented.
Obi source moved to Google Code
I’ve just moved the Obi code from the internal Workingmouse repository to Google Code. Behold the shiny new home of Obi. Still not much to see, you’ll need to grab the source.
Path composition in Obi
Over the last few days I’ve been progressing steadily with Obi, my Scala-based build tool. I’m starting at the bottom level, building some low level primitives that can then be combined into higher level layers (examples at the end of this post).
Here’s the first simple example, it represents a path to a file on the filesystem.
import org.obi.io.file.FilePath._
// Create a FilePath
val p1 = filepath("/foo/bar.jar")
val p2 = path("/foo/bar.jar")
// Implicit conversion from String to FilePath
val p3: FilePath = "/foo/bar.jar"
// Implicit conversion from FilePath to String
val p4: String = path("/foo/bar.jar")
FilePaths can also be combined to form classpaths (I’m working on javac). Here’s some examples of the way you can create classpaths, each of the these will give the classpath string /foo/bar.jar:/foo/baz.jar (on a *nix box). All are syntactically valid Scala, syntax requests/suggestions are welcome, these are some that I came up with, that’ll probably change once it’s used inline in the compilation task.
import org.obi.attr.ClassPath._
import org.obi.io.file.FilePath._
val cp1 = classpath("/foo/bar.jar", "/foo/baz.jar")
val cp2 = classpath(List("/foo/bar.jar", "/foo/baz.jar"))
val cp3 = classpath < < "/foo/bar.jar" << "/foo/baz.jar"
val cp4 = classpath << List("/foo/bar.jar", "/foo/baz.jar")
val cp5 = "/foo/bar.jar" <<: classpath("/foo/baz.jar")
val cp6 = List("/foo/bar.jar", "/foo/baz.jar") <<: classpath
val cp7 = "/foo/bar.jar" << classpath << "/foo/baz.jar"
val cp8 = classpath("/foo/bar.jar") << classpath("/foo/baz.jar")
val cp9 = classpath("/foo/bar.jar") ::: classpath("/foo/baz.jar")
val cp10 = classpath("/foo/bar.jar") + classpath("/foo/baz.jar")
val cp11 = classpath("/foo/bar.jar") + "/foo/baz.jar"
val cp12 = "/foo/bar.jar" :: classpath("/foo/baz.jar")
val cps: String = classpath << "/foo/bar.jar" << "/foo/baz.jar"
With these kind of primitives, it’d be pretty easy to create abstractions such as “library” which would enable a feature such as Maven’s dependency management using a syntax similar to buildr’s. Here’s a simple example of what’s currently implemented, syntax can be cleaned up.
val log4j = path("log4j.jar")
val cglib = path("cglib.jar")
val commons_logging = path("commons-logging.jar") < <: log4j
val ehcache = commons_logging << "ehcache.jar"
val hibernate = ehcache + commons_logging + cglib
There’s no way to “resolve” dependencies as yet (and won’t be for a while) and you get duplicates in the path. But, this would open up things such as (I’ve no idea if this is valid syntax, I doubt it is):
val hibernate = library(
dependencies |= ehcache + commons_logging + cglib,
version "3.2.5.ga")
All in all I think the syntax is quite readable and flexible, it’s also strongly typed. Writing these kinds of DSLs has proved very easy using Scala, I’m quite impressed.
Scala varags handling
Mainly for my future reference, a quick overview of how Scala appears to handle varargs. The Scala book doesn’t offer an explanation currently so this is all derived through experiments using Scala 2.6.1.
To make a method accept a variable number of arguments, it is defined as follows.
scala> def foo(s: String*) { println(s) }
foo: (String*)Unit
Like Java, Scala requires the vararg to be the last parameter to the function. Once in your method, the parameter is of type Array[String] (more generally Array[A] where A is a type parameter).
scala> def foo(s: String) { println(s) }
foo: (String)Unit
scala> foo("hello")
hello
scala> def foo(s: String*) { println(s) }
foo: (String*)Unit
scala> foo("hello", "world")
Array(hello, world)
scala> def foo(s: String*, t: Int) { println(s) }
:4: error: *-parameter must come last
def foo(s: String*, t: Int) { println(s) }
^
Unlike Java 1.5, you must explicitly declare your functions to accept variable arguments, you can not declare a parameter to be an Array[A] and have the runtime perform an automatic conversion for you (I believe this may have something to do with Java 13/1.4 compatibility). So the following is not equivalent to the above and will not compile:
scala> def foo(s: Array[String]) { println(s) }
foo: (Array[String])Unit
scala> foo("hello", "world")
:6: error: wrong number of arguments for method foo: (Array[String])Unit
foo("hello", "world")
^
Likewise, you can not declare something to take a varargs parameter and call it as if it’s an array (as you can in Java):
scala> def foo(s: String*) { println(s) }
foo: (String*)Unit
scala> foo(Array("hello", "world"))
:6: error: no type parameters for method apply: (A*)Array[A] in object Array exist so that it can be applied to arguments (java.lang.String,java.lang.String)
--- because ---
result type Array[A] is incompatible with expected type String
foo(Array("hello", "world"))
^
There’s also some odd rules around overloading of functions, due to erasure:
scala> object Foo { def foo(ss: String*) = println(ss); def foo(is: Int*) = println(is) }
:4: error: double definition:
method foo:(Int*)Unit and
method foo:(String*)Unit at line 4
have same type after erasure: (Seq)Unit
object Foo { def foo(ss: String*) = println(ss); def foo(is: Int*) = println(is) }
The variable argument gets the type Seq[A] (the actual underlying runtime type is Array[A]), and owing to the wonderful properties of erasure, both these methods have the same signature.
Scala for Java refuges
Daniel Spiewak has a series of posts (1 through 3 currently) on introducing Scala to Java developers.
Anonymous commenting switched off
In an effort to reduce the amount of spam I have to deal with via this blog (roughly 3000 per week, of which 50 odd get through the Akismet filter), I’ve turned off anonymous posting. You will now need to enter a name and address to post comments. Apologies if this affects anyone adversely.
Obi is born
In an effort to learn Scala I’ve been playing around with creating a build tool, called Obi. This is nothing more than me looking for a nice way to learn Scala, but after a couple of days of thinking it looks quite doable.
Obi has three goals; 1) allow me to learn Scala, 2) provide a nice DSL that is expressive and allows use of Scala APIs and idioms and 3) provide the type safety of the Scala language, e.g. a javac task will not compile if you do not pass it a source file.
Here’s an example of the current syntax we’re playing with, this doesn’t actually do anything as yet, but does compile (well, most of it compiles). Each call is pure (side effect free), you need to apply the ! to actually execute the tasks.
import SrcDir._
import Javac._
import AntJavac._
// Two compile targets, Java code and Scala code
val jc = javac(srcdir("src/main/java")).srcfiles(
List("Foo.java", "Bar.java"))
val sc = scalac.srcdir("src/main/scala").srcfiles(
List("Foo.scala", "Bar.scala"))
// Equivalent of an Ant "target", Java compile is performed
// before Scala compile, both tasks are executed when called.
def compile {
!jc
!sc
}
// Compile Foo.java & Bar.java in src/main/java
!javac(srcdir("src/main/java")).srcfiles(
List("Foo.java", "Bar.java"))
// Create a compile for Foo.java & Bar.java in src/main.java
List("Foo.java", "Bar.java") >>: javac(srcdir("src/main/java"))
// Create a compile for all files in src/main.java
Dir("src/main/scala") >>: scala(srcdir("src/main/scala"))
// compile all Scala source files in an "obi" directory
val scalaCompile = Dir("src/main/scala")
.filter(_.matches("""obi.*\.scala$""")) >>: scalac
!scalaCompile
For those that want to look at other Scala tools, it looks like the only tool available currently is SAnt, Maven and Ant.
If you are interested, Obi is not named after Obi-Wan Kenobi, but after Obi Obi Creek on the Sunshine Coast of Queensland (where I’m doing a throughwalk later this year).
Bring bad design to justice
Via Justin French:
scala.Option Cheat Sheet
Tony has a nice post on using Scala’s Option type:
Many people who are coming in to Scala first encounter the Option type, which may be thought of (among other things) as a type-safe null. They also encounter pattern matching as both a new and (relatively) powerful concept, but also one that is easy to understand. This leads to quite a lot of use of pattern matching and often excessively so in what I have observed.
Particularly with a type as trivial as Option, it is almost always possible to do away with pattern matching by using a higher-order function. Use of this function is typically preferred over pattern matching as tighter code.
Source: scala.Option Cheat Sheet.
Refuse The Terror
Via Bruce Schneier comes Refuse the terror, very American focused, but good none the less, all I can say is I’m very glad the our previous Government was voted out of office.
See also Downsize DC, a group that appears to have similar aims of reducing the fear.
