(I'm drafting this at the moment. Feedback appreciated - tom@tommorris.org )
A lot of guides to Scala are written with an intended audience of academics and computer scientists, partly because Scala's development by Martin Odersky at EPFL means it's quite an interesting language on a purely intellectual level. Scala doesn't seem to be designed simply as a research project though: it's designed as a practical language. Here it fits a rather unique niche: it is supposed to be useful both for programmers who work in scripting languages (however you choose to define them) like Python, Ruby or Perl and for people more familiar with languages like Java, C# and C++. It really has the benefits of both. As a language, it has a strong type system, but you don't have to make explicit type declarations - instead, the compiler or interpreter will be happy to work out that in `var foo = 9` a different type is being instantiated than in `var foo = "9"`. The language also imports a lot of the constructs of functional programming languages like Haskell into a language that's strongly OO.
But is it a language for hackers? By hackers, I don't mean kernel hackers. I mean people who build small hacks - who use whatever technology is at hand to achieve some interesting end-goal. Hackers need to be able to do the really easy things quickly. BarCamps and HackDays require one to be able to turn around an idea overnight: a valuable skill in the commercial world also! Being able to rapidly prototype is a useful skill: it means you can "throw one away" quicker, you can drop ideas that are impractical and move on, and it means you can actually show something the next day and make people say 'Wow'.
I think that Scala could be a perfect language for them. I'm not sure of it. Unfortunately, the current Scala introductions tell them how to produce a good quicksort or use something like combinatorial parsing before telling them how to, say, read an Atom feed.
Scala guys may respond: "ah, but you just use the underlying Java". To which the non-Scala user says "okay, what's that?". Scala for Hackers is intended to solve this.
As I said, I'm not sure of it. Writing this document is a way for me to try and document the various things I'm doing with Scala. Hopefully Scala nerds might be able to use it to write libraries to make this stuff easier.
Theory
Obviously, you need to learn the basics of Scala before hacking with it. If you learn from dead-tree media, I suggest Odersky, Spoon and Venner's "Programming in Scala" (Artima) or Wampler and Payne's "Programming Scala" (O'Reilly)
Introspection
If you use Ruby, you often want to see what methods exist on a class or object, so you do something like `"foo".methods`
In Scala, you can call 'getMethods' on a class, meaning you can do something like this:
"foo".getClass.getMethods.foreach(println _)
Here, the string "foo" is getting instantiated - Scala will figure out it is a string, then ask the instance to return the class. getMethods returns an array of the methods from the class. foreach loops across the array and (println _) prints 'em out.
But what if you don't want to instantiate the class to introspect on it's methods?
Class.forName("java.lang.String").getMethods.foreach(println _)
Class.forName is just taken from Java. getMethods returns an array of java.lang.reflect.Method objects (as opposed to Ruby which just returns an array of strings). The Method class is useful as you can use it to see what methods return what types, or take particular types as arguments. getReturnType() returns a Class object for
Here is an example of reflection I used when writing the XML parsing section:
(doc\\"h1")(0).getClass.getMethods.filter(_.getReturnType() == Class.forName("java.lang.String")).foreach(println _)
This takes the first h1 element in the document 'doc', gets all the methods one can call on that class, filters them to only those whose return strings and print those out. This way, I can figure out how out the 'get back a text node as a string' method - it's just called 'text'.
See the StackOverflow question Scala: How do I dynamically instantiate an object and invoke a method using reflection?
Practice
Prerequisites
Using Scala, there are two ways you need to go about getting libraries. First, there's sbaz - Scala Bazaar. But not everything is in sbaz. In fact, most libraries you'll want to use aren't. So you need to get them as JAR files.
sbaz (output of `sbaz installed`):
- base/1.9
- commons-logging/0.0
- httpclient-4/0.0
- httpcore-4/0.0
- log4j/1.2.13
- sbaz/1.25tmp
- sbaz-setup/1.0
- scala/2.7.5.final
- scala-devel/2.7.5.final
- scala-library/2.7.5.final
- scala-tool-support/2.7.5.final
- uncarved-helpers/0.3
JARs - this is from my ~/code/classes/:
- antlr-2.7.5.jar
- commons-beanutils-1.8.2.jar
- commons-codec-1.3.jar
- commons-collections-3.2.1.jar
- commons-lang-2.4.jar
- commons-logging-1.1.1.jar
- commons-logging-api-1.1.1.jar
- concurrent.jar
- dispatch-http_2.7.7-0.6.6.jar
- dispatch-json_2.7.5-0.6.6.jar
- ezmorph-1.0.6.jar
- httpclient-4.0.1.jar
- httpcore-4.0.1.jar
- icu4j_3_4.jar
- iri.jar
- jena.jar
- jenatest.jar
- json-lib-2.3-jdk15.jar
- json.jar
- junit.jar
- log4j-1.2.12.jar
- log4j-1.2.15.jar
- lucene-core-2.3.1.jar
- stax-api-1.0.jar
- wstx-asl-3.0.0.jar
- xercesImpl.jar
- xml-apis.jar
Talking to the Web
Obviously, the first thing you need to be able to do is talk to the Web. That means using HTTP.
There are three ways of doing this at the moment:
Also see the IBM developerWorks article Scala and XML.
Using the Dispatch library we installed using sbaz, let's get something off the web:import dispatch._import Http._var http = new Http()var helloscala = http("http://tommorris.org/files/helloscala.txt" as_str)
Parsing XML
You can parse XML natively in the language using the scala.xml functionality.
import scala.xml._val string = /* whatever */val doc = XML.loadString(string)(doc\\"h1")(0).text
Parsing JSON
If you want a native Scala library, try scala-json. Alternatively, use json.jar from Java.
My preferred way of parsing JSON is using json-lib. Here is how you parse json-time using Scala.
First, I am using the following CLASSPATH:
scala -cp $CLASSPATH:commons-lang-2.4.jar:json-lib-2.3-jdk15.jar:ezmorph-1.0.6.jar:commons-collections-3.2.1.jar:commons-beanutils-1.8.2.jar
Here's the code:
import dispatch._
import Http._
import net.sf.json._
var http = new Http()
var jsontime = JSONObject.fromObject(http("http://json-time.appspot.com/time.json" as_str))
Now we can interrogate the object a bit:
jsontime.get("tz").asInstanceOf[String]
jsontime.get("hour").asInstanceOf[Int]
(Obviously, if we are going to use date/time objects, we should probably import JodaTime and scala-time and cast the objects returned from the JSONObject into the relevant date-time objects.)