There's been a lot of chatter lately about static vs. dynamic languages, code size, code density, etc. Many people lump Scala into the statically typed bucket because Scala has static typing. But what most folks don't realize is that Scala has most of the flexibility and syntactic economy of languages like Ruby and Python while supporting compiler checking of types to flag errors.
You may be confused. Over the next few postings, I'm going to demonstrate that most of the safe (taking input off the wire and doing method lookup on that input is not safe) constructs that dynamically typed languages have are available in Scala.
But first, you have to read the following:
If you think I'm a crappy programmer and want to make posts about my stupidity and your superiority, go someplace else. But before you do, take a look in the lift repository. Most of that code is mine. I'm not the best programmer I've ever met, but I'm not stupid or some variant.
I've been coding professionally for nearly 30 years. I've used virtually every popular language for commercial projects (except Lisp.) I've done nearly 2 years of Ruby. I've done 11 years of Java. I built the first real-time spreadsheet (Mesa) in a combination of Objective-C and C++. I understand, very, very intimately the difference between statically typed and dynamically typed languages. This isn't to say I can't learn more, but for those who have 2 years of Ruby under their belt after a couple of 200 level Java classes in college, don't bother flaming me.
So, one of the places that dynamic languages shine is the ability to pass an object (or a collection of objects) to a method and as long as the objects implement particular methods (e.g., name and age), the method will execute just fine. For example, a method that returns a string formatted with the name and age of each of the objects in the collection. This is particularly useful for functions that format instances of classes that have similar method naming, but not a similar base class.
Just like Ruby and Python, Scala can do this. The only thing that you have to do is declare the methods that the objects must implement as the "type" of the incoming parameters. Think of this extra "typing" as merely good documentation.
First, let's define a couple of classes:
case class Pet(name: String, age: Int, price: Int) case class Antique(name: String, year: Int, cost: Int) { def age = 2008 - year }
In Scala, case class creates a class that can be economically instantiated (no need for 'new') and has accessors for its parameters as well as deep comparators, toString, and hashCode methods.
Next, let's create some collections of Pets and Antiques:
Cool. It works like Ruby and Python. Yeah, yeah, you have to write a little extra stuff describing the methods used. So what? You want to do this anyway because it's part of documenting your code. The 20 or so characters are characters that wind up in the HTML documentation of the method. And, you get some free tests for this method because if you try to call it with parameters that don't match, the compiler flags the problem for you. You save some typing because you can write fewer tests.
But it gets better with Scala. If you don't have a uniform naming convention (for example, Pet has a price property and Antique has a cost property.) So in Ruby and Python, you can't use the same method to format the name and price/cost of both Pet and Antique. In Scala, there are two ways to do this using some excellent mojo called "view bounds".
You can define a lightweight class that contains just name and price: NameAndPrice. Next, you define a method that takes a list of things that can be converted into a NameAndPrice (that's what the <% means.)
The next thing to do is define a method that converts Pet or Antique into a NameAndPrice. You only need to define this method once and the method will be applied to all cases where you need to convert from Pet or Antique to NameAndPrice:
But it gets even better. We can combine these two mechanisms to allow arbitrary classes to be passed to a method and do implicit conversion if the class doesn't have the cost method but has a price method. First, let's look at a variant of the original example:
So, Scala can do everything that Ruby and Python can do in terms of taking objects or collections of objects and "dynamically calling methods on them. But Scala does them one better with the ability to normalize method names across classes so you can use the same methods for classes with different naming conventions.
There are a couple of "points" that folks may make about this code:
Those "implicit" things look really dangerous. They can be, but they are also scoped so one "invites" the implicit conversions into a module with an import statement. They are far less dangerous than AOP or Ruby's meta-programming/open classes, yet they serve the same purpose.
There must be some performance penalty for not using classes, but just calling things by method name. Yes, there is, but the JVM HotSpot compiler mitigates this issue. The cost of one of these method calls is about 5x the cost of a regular method call... or about the same as the cost of a Ruby method call vs. a Java method call. The nice thing is you only have to use them when you need them, so the performance hit is localized rather than a global problem with all your code.
All this creation of objects much cost a lot garbage collection-wise. Actually, no. The JVM's generational garbage collector is optimized for situations like this and because the implicitly created objects are short-lived, they'll GC very nicely.
That's it for the first installment. In the next installment, I'll show you have to dynamically change an object dispatch table at run-time so you can create your own proto-type style classes and then change the class behavior at runtime.
Project Euler is a site with mathematical puzzles that can be solved relatively quickly with an efficient algorithm. Randall Munroe (of xkcd fame), used Project Euler to become more acquainted with Python, so I thought I'd give it a shot in Scala. I'll be using the Scala interpreter, which comes with any standard Scala installation.
Familiarity with Scala is not necessarily required, as I've attempted to also make this a whirlwind tour of some of Scala's more interesting features: implicit conversions, anonymous functions, anonymous parameters, type inference, lazy evaluation, Pimped Libraries, and sequence comprehensions. I also go through some of the methods in Scala's standard library, particularly for some of the collection classes. I don't attempt to explain all these things in detail, but I've provided links for the curious.
Warning: Puzzle spoilers ahead. Also, these algorithms are by no means optimal, but they're "fast enough" and they get the job done.
Problem 1: Find the sum of all the multiples of 3 or 5 below 1000.
This is fairly easy. The until method (defined on Ints via an implicit conversion to RichInt) lets us construct ranges of numbers.
scala> 1 until 10 res5: Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
We can use the filter method to grab only those numbers that are multiples of 3 or 5.
scala> (1 until 10).filter(n => n % 3 == 0 || n % 5 == 0) res6: Seq.Projection[Int] = RangeF(3, 5, 6, 9)
We're using Scala's syntax for anonymous functions. If you're unfamiliar with Scala, it might seem like "n" is dynamically typed. In fact, Scala's type inference allows "n" to be statically typed (as an Int) at compile time, even though we omitted the type declaration.
And finally we can use foldLeft to sum up all the numbers.
scala> (1 until 1000).filter(n => n % 3 == 0 || n % 5 == 0).foldLeft(0)(_ + _) res2: Int = 233168
Here the underscores in (_ + _) act as anonymous parameters for an anonymous function. The first underscore represents the first parameter, and the second underscore represents the second parameter. Pretty cool!
Problem 2: Find the sum of all the even-valued terms in the Fibonacci sequence which do not exceed one million.
First we need to define the Fibonacci sequence. We'll define it lazily using Scala's "lazy" construct and the Stream class.
This manually defines the first two terms of the Fibonacci sequence, then recursively defines an infinite stream of the remaining Fibonacci terms. fib is the Fibonacci sequence starting at zero (0, 1, 1, 2, 3, ...). fib.tail is the Fibonacci sequence starting at one (1, 1, 2, 3, 5, ...). fib.zip(fib.tail) is the two sequences zipped into a sequence of pairs ((0, 1), (1, 1), (1, 2), (2, 3), ...). We then use map to sum the two parts of each pair (._1 and ._2) and complete the recursive definition of the rest of fib, after the first two terms (1, 2, 3, 5, ...).
Thanks to Stream, the terms of the Fibonacci sequence are only evaluated as they are needed, so we can represent an infinite stream without incurring infinite computation.
We can verify that we computed the Fibonacci numbers correctly by inspecting the first few terms of our Stream with take and print.
That looks about right. Now lets filter so we only have the even-valued Fibonacci terms, use takeWhile to grab the terms below a million, and add them up. Since I'm getting tired of foldLeft, let's Pimp my Library and add a "sum" method to our Fibonacci sequence (indeed, to any Iterable[Int]).
scala> implicit def iterableWithSum(it: Iterable[Int]) = | new { def sum = it.foldLeft(0)(_ + _) } iterableWithSum: (Iterable[Int])java.lang.Object{def sum: Int}
Problem 3: What is the largest prime factor of the number 317584931803?
We could define an infinite stream of prime numbers using the Sieve of Eratosthenes or some other technique for finding prime numbers, but this example is simple enough that we don't have to bother.
Let's recursively define an infinite stream of natural numbers and verify that it works as we intend.
If we define the number we want to factor as a mutable var, we can use a combination of functional and imperative programming (fairly unique to Scala) to find the largest prime factor.
scala> var theNum = 317584931803L theNum: Long = 317584931803
We keep dividing down theNum until it has no factors left, then we return the last (largest) factor we used. By definition all the factors we divide by will be prime.
scala> naturals.dropWhile(n => if (theNum % n != 0) true else {theNum /= n; theNum > 1})
If a natural number is not a divisor of theNum, we drop it. If it is a divisor, we divide-and-update theNum, and drop it if theNum is still greater than 1. By updating theNum, we assure that all the divisors we find are prime. By stopping when theNum reaches 1, then the first number in our remaining stream will be the largest prime factor we want.
Problem 4: Find the largest palindrome made from the product of two 3-digit numbers.
We'll need to check for palindromes, so this could come in handy:
We can use sequence comprehensions to generate all the products of three digit numbers that are palindromes.
scala> val palindromes = for (a <- (100 until 1000); | b <- (a until 1000); | val p = a*b if isPalindrome(p.toString)) | yield p palindromes: Seq.Projection[Int] = RangeG(10201, 11211, 12221, 13231...
Now we can sort and grab the largest palindrome with head.
scala> palindromes.toList.sort(_ > _).head res52: Int = 906609
Problem 5: What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?
I'm going to cheat here, because this is easier to do by hand:
scala> 2*3*2*5*7*2*3*11*13*2*17*19 res0: Int = 232792560
And that's a little fun with Project Euler and Scala!
I'm am very pleased to announce that the lift web framework version 0.3.0 is now available.
lift is a secure, simple, powerful web framework for building real-time collaborative applications. lift is written in Scala, the functional/OO hybrid language that runs on the JVM and is completely interoperable with Java and Java libraries. lift applications deploy as WAR files on servlet engines supporting Servlet 2.4 and greater including Jetty and Tomcat.
First... some thanks... then the new features... then some goodies...
I'd like to thank the amazingly awesome lift committers... a growing team of extraordinary people. Since 0.2.0, lift has gone from being a near solo effort to being a group effort. David Bernard has done an awesome job of adding process, mainly in the form of Maven, to lift. Steve Jenson, Jorge Ortiz Hinojosa, and Viktor Klang have committed new features and enhancements into the code base. And Daniel Green, the lift outreach guy, has kept us excited and started the drum-beat to tell the world about the benefits of using lift. I'd also like to thank Gregory Brown of Ruport fame for showing me how to build an open source community.
Support for new O-R mapped field types including Country, Locale, Time Zone, Postal Code, etc.
Lots of new example code including a real-time blog
Improved XHTML support for modern browsers
Support for multiple database instances
Improved regular expression support including regex -> object creation for simple parsers
A new and improved Textile parser
Much more documentation, both in the form of ScalaDocs and in the form of an wiki with lots of excellent code
While the new feature list is impressive, what is more important is that the lift APIs are settling and lift is becoming ready to build real applications.
There are half a dozen projects currently being built on lift and Much4 has been up and running and helping me organize my life.
So... the good stuff:
There's a new Scala Blog. It's a central point for lift and Scala related blogging including an excellent example of building Digg in < 140 lines of code
The "Programming in Scala" book will be available in draft version very soon
The lift wiki has lots of budding tutorials, documentation, and frequently asked questions, etc.
The lift mailing list hit 600 posts last month and is now a "medium volume" Google Group
And... Daniel Green is the lift outreach guy (yeah, I said it already... but it's worth saying again.)
Please download Maven and Java... that's all you need to build a lift application. Type: mvn archetype:create -U \ -DarchetypeGroupId=net.liftweb \ -DarchetypeArtifactId=lift-archetype-blank \ -DarchetypeVersion=0.3.0 \ -DremoteRepositories=http://scala-tools.org/repo-releases \ -DgroupId=com.test -DartifactId=ilikeit
And that's all there is to starting out with lift. If you like it... join the mailing list, ask questions, give feedback... If you don't like it... give feedback.
In an effort to realize the "grow together" spirit, the developers of lifthave teamed up with other great minds in the Scala community to bring you Scala-Blogs.org. Our mission is to strengthen the community by sharing our experiences and knowledge so that others can learn from our mistakes and triumph along with our successes.
At Scala-Blogs.org you will find tutorials and articles written by a growing host of enthusiasts, each with a different background and area of expertise. In the course of only a few days, they have already made Scala-Blogs.org home to several intriguing posts. Take a look at the "blog archive" list on the right and begin your journey!
We want Scala and lift to enjoy the success they deserve, so join us in promoting this blog and aid us in our efforts to explore the potential of Scala; share the news with your friends and coworkers, blog about us and urge others to do the same, and, most importantly, read and enjoy.
One of my favorite things about Scala is it's Actor library.
Messaging has become an important part of modern architecture for the web. Many of the large scale web sites that are popular today are using message queues as infrastructure for processing requests. Scala Actors help us use those ideas in lift. Recently we added AMQP support to lift by wrapping RabbitMQ's client libraries with Scala Actors. Scala Actors make it easy to model the consumer/producer paradigm that's so prevalent in modern messaging systems.
Another thing I love about Scala Actors is combining them with my favorite functional combinators to make useful data structures. Recently, for lift, I wrote some example code that I felt could benefit from a cache. 30 lines of Actors and functional combinators later and I had a full-featured cache where listeners could register and be updated when the state of the cache changed.
Actors are a wonderful tool for software design. If you want to learn more about them, I recommend reading the Scala Actors papers.
I want to show you a simple program that matches regular expressions (regexps), which demonstrates rather nicely what makes functional programming so appealing. You probably know what regexps are and that they can be turned to state machines and so on...
Let's forget about that for a moment. Let us start from scratch.
Well, not entirely from scratch. Speaking the words of theory, we say, a *word* w is either the empty word, a single *letter* c, or the concatenation of two words w1,w2. A regular expression then describes a set of words that all have a particular structure in common.
In order to write down regexps in Scala, we need to define the building blocks. And since we would like to keep the door open to matching other things than strings of characters, these building blocks should be generic. Here is the code.
abstract class RegExp[A]
case class Phi[A]() extends RegExp[A] case class Empty[A]() extends RegExp[A] case class L[A](letter:A) extends RegExp[A] case class Choice[A](left:RegExp[A], right:RegExp[A]) extends RegExp[A] case class Seq[A](left:RegExp[A], right:RegExp[A]) extends RegExp[A] case class Star[A](exp:RegExp[A]) extends RegExp[A]
We can now directly write things like Choice(L('a'),Star(L('b'))). Here is what these expressions mean:
Phi matches nothing Empty matches the empty word L(c) matches the single letter c Seq(r1,r2) match all words w1,w2 where w1 matches r1 and w2 matches r2 Choice(r1,r2) matches all words w that match either r1 or r2 (or both) Star(r) matches all words w1,...,wn where each of the wi matches r.
Now how can we write code that follows these definitions? Our first try might be a recursive function accepts that takes a regexp and a word and returns a boolean. Whenever a regexp contains another regexp, we could then call accept recursively, with suitable new input. Most rules seems easy, like for Choice we can try to match the input against r1 and if that doesn't work out, we would try r2. However, for Seq and Star we would have to cut a word in pieces and match the pieces against the regexps, possibly backtracking and trying out other ways to cut the word in pieces. That is quite inefficient.
It turns out there is a better way: A word can obviously only match if each of its letters were matched by some part of the regular expression. So why don't we take each letter, and try to "consume" it with some part of the regular expression. If we can play this game until no letters are left, this means the word is accepted. The key to making this work is to represent the "remaining" expression. But hey, don't we have everything there to represent expressions? We could just build the remaining expression as we go.
Here is the full program. Check out the partDeriv function, which computes the 'derivative' of a regular expression with respect to an input letter.
object Main { abstract class RegExp[A] case class Phi[A]() extends RegExp[A] case class Empty[A]() extends RegExp[A] case class L[A](letter:A) extends RegExp[A] case class Choice[A](left:RegExp[A], right:RegExp[A]) extends RegExp[A] case class Seq[A](left:RegExp[A], right:RegExp[A]) extends RegExp[A] case class Star[A](exp:RegExp[A]) extends RegExp[A]
type Word[A] = List[A]
def matchRegExp[A](re:RegExp[A], w:Word[A]): Boolean = w match { case List() => acceptsEmpty(re) case c::w1 => matchRegExp(partDeriv(re, c), w1) }
def acceptsEmpty[A](re:RegExp[A]): Boolean = re match { case Phi() => false case Empty() => true case Choice(r1,r2) => acceptsEmpty(r1) || acceptsEmpty(r2) case Seq(r1,r2) => acceptsEmpty(r1) && acceptsEmpty(r2) case Star(r) => true case L(_) => false }
def partDeriv[A](re:RegExp[A], c:A): RegExp[A] = (re, c) match { case (Phi(), _) => Phi() case (Empty(), _) => Phi() case (L(c1), c2) if (c1 == c2) => Empty() case (L(c1), _) => Phi() case (Choice(r1,r2), c) => Choice(partDeriv(r1,c),partDeriv(r2,c)) case (Seq(r1,r2), c) => val rn = Seq(partDeriv(r1,c),r2) if (acceptsEmpty(r1)) Choice(rn, partDeriv(r2,c)) else rn case (rs @ Star(r), c) => Seq(partDeriv(r,c),rs) }
def main(args:Array[String]): Unit = { println matchRegExp(Choice(L('a'),Star(L('b'))), List('b','b','b')) } }
What do you know? Pattern matching and recursive calls. Not a single imperative update. It doesn't even use anonymous functions. The program looks remarkably similar in Haskell.
I could now go and try to explain why the partDeriv function does what it does, but you wouldn't learn anything from it. There are two things that are helpful to understand why this works: one is calculating what the function does "by hand", using sample inputs (feel free to insert debug print statements and run it if you are too lazy for that). And, if that is not enough, read the theorem and proof on the 1964 paper by Janus A. Brzozowski which is called "Derivatives of Regular Expressions" JACM 11:4 pp 481-494.
What it comes down to is that some computational problems have a structure to them that permits elegant solutions. David Pollak has summed it up nicely when he said about Scala "what it does is, it reduces code to its essence". Not every problem will have an elegant purely functional solution, but conciseness and clarity have their place in every software engineering project. Now enjoy finding the essence of your code.
Scala makes for a great language to experiment with programming language design. In my upcoming posts, I'll address applications such as:
parsing I'll explain how to get your parser up and running in no time, without resorting to external tools. Scala comes with an easy to use library of parser combinators, which means there's no extra tool to integrate in your build process, no weird generated code to debug, and no new language to learn. Well, that last part is a bit of a fib, as the library of parser combinators essentially implements a domain-specific language in Scala itself!
variable binding and substitution Getting substitution right is trickier than most people think. We'll look at a library that encapsulates all this, and which integrates nicely with Scala's parser combinators to express variable scoping right in your language's grammar.
type-checking We'll see how you can "port" the inference rules that define your type system from paper to Scala, with most of the boilerplate hidden underneath the covers of a type-checking monad.
My colleagues and I are happily using these libraries, and I hope to convince you to do the same (once I get around to documenting them and preparing them for release ;-) -- RSN!).
This is a tutorial introduction to building dynamic web applications with lift and Scala. We'll be building a linksharing site, much like Digg or reddit. However, lift's advanced support for Comet-enabled web applications will allow our site to update live as new links get submitted or old links get voted up or down, without our visitors having to refresh the page.
This is a short (50 seconds) screencast of what we're trying to build. The quality on the YouTube version isn't great, so you can also download the full-quality QuickTime version (~800K). I'm running two different browsers, Safari and Camino, and loading the finished site with both of them. Notice how the link submissions and votes made in one browser get automatically updated in the other browser. We accomplish this using Comet, and we'll see how lift makes Comet-enabled web applications a breeze. Let's get started.
I'll assume that you have the most recent versions of Scala, Eclipse, the Scala Plugin for Eclipse, and Maven installed. I'll also assume you have some rudimentary knowledge of Scala.
(I've you have used lift before the 0.3.0 release on Dec. 7, there is a bug in our repository that might cause you to use a pre-release version of the lift libraries. To fix this problem, delete the net/liftweb directory in your local Maven repository before continuing. I believe the default location is: ~/.m2/repository/net/liftweb)
From Eclipse's workspace directory, lets create a new project called "linkshare" in the "com.test" package by typing the following into the command line:
That's all we need to do to set up a skeleton lift site. (If you're using Eclipse and want to use Q4E, see: http://liftweb.net/index.php/Archetypes) Now we'll go into the directory that contains our project and run it with Jetty. Maven should automatically download Jetty for you if you don't already have it.
cd linkshare mvn jetty:run
If everything goes well, you should be able to see your skeleton lift site running on http://localhost:8080/. We see a nice welcome screen that shows the current time. Now let's do something with the site. Leave Jetty running, and open the index.html file in src/main/webapp. Edit the file so that it contains a more topical message, like "Welcome to your linksharing site!". Save the file and reload your browser. Your changes should have been picked up by Jetty.
Jetty also automatically picks up on changes to your compiled class files and redeploys your webapp when necessary, so you can leave the Jetty process running throughout this tutorial and see the changes in your browser. We'll still want to do some stuff on the command line, so open up another command line window. Then create an eclipse project with the following command:
mvn eclipse:eclipse
Now you can import the lift project into Eclipse. There are two directories you should mostly be concerned with. The src/main/scala directory contains all the Scala code for your lift project, while the src/main/webapp directory contains the html, css, javascript, etc.
You'll probably want to enable Eclipse's incremental compilation. That way, whenever you save changes to your code, Eclipse will recompile your .class files, and Jetty will pick up the new code. If you're not using Eclipse, or not using incremental compilation, you'll want to issue a 'mvn compile' command to see any changes to your code reflected in Jetty.
You'll notice that our app's page has a "Home" link which points right back to the main page. This is actually a part of lift's advanced Sitemap feature, but for now we won't be using it, so let's disable it.
The Sitemap is defined in our bootstrap. Our site's bootstrap code gets run by lift as soon as our app gets deployed. This is a great place to make sure we set up our databases correctly, among other things. It's also where our Sitemap is defined, so let's go take a look.
You'll find the bootstrap code in src/main/scala/bootstrap/liftweb/Boot.scala. It's fairly lonely in here, as our app doesn't do much yet. Let's modify the appropriate line to hide the "Home" link from our Sitemap. We do this by adding the "Hidden" argument, like so:
val entries = Menu(Loc("Home", "/", "Home", Hidden)) :: Nil
Save the file, then wait a few seconds for Jetty to pick up the changes. (If you're not using Eclipse's incremental compilation, then you'll have to issue a 'mvn install' command.) When you refresh your site's page, you should see that the "Home" link has disappeared. Awesome! Now let's do something useful.
Our first order of business is to allow our visitors to submit links. If we want to receive links from our visitors, then we also want somewhere to keep those links. At this point, most people would start defining database connections, database schemata, model objects, object-relational mapping... Doing all of this is very easy with lift. The included Mapper classes provide a great way of easily, securely, and meaningfully storing your bytes.
However, I'm going to make a controversial decision: we won't use a database. lift, you see, is a highly stateful web framework. It keeps state around between requests, so we can get very far without a database. Of course, this means that if our app gets redeployed, or if it goes down for maintenance, or if it crashes, then we'll lose all of our state and we'll have to start collecting links from scratch. This is clearly unacceptable in a production environment, where we would want to persist our important information to a database. Like I said, lift makes this easy with the included Mapper classes. However, for the purposes of this demo, we can deal with losing all of our links every now and then.
So if we're not keeping our links in a database, then where are we keeping them? We're going to use a long-lived Scala Actor. Scala Actors are lightweight threads, similar to Erlang's Actors. They can send and receive messages to other Actors, which will come in very handy. Let's make a LinkStore object in our com.test.controller package:
// Messages case class AddListener(listener: Actor) case class RemoveListener(listener: Actor) case class UpdateLinks(topLinks: List[Link]) case class AddLink(url: String, title: String) case class VoteUp(linkId: String) case class VoteDown(linkId: String)
// Data Structures case class Link(id: String, entry: LinkEntry) case class LinkEntry(url: String, title: String, var score: Int)
object LinkStore extends Actor { val linkMap = new HashMap[String, LinkEntry] val listeners = new HashSet[Actor] var topLinks: List[Link] = Nil
The central data structure here is the LinkEntry. It stores the url, title, and current score of a link. Our LinkStore is a singleton Actor which is started up when the class is loaded. The LinkStore keeps a HashMap of LinkEntries, indexed by a unique ID of 12 characters. The LinkStore responds to three messages that can modify the LinkEntries: AddLink, VoteUp, and VoteDown. Each does what its name suggests. The LinkStore also keeps a HashSet of listeners. Listeners are other actors that want to be notified when the LinkStore changes. Registered listeners are sent the newest list of Top 20 Links whenever there is an update.
Now that we have a place to store our links, we want to let our visitors send them to us. If you take a look at index.html in src/main/webapp, you'll notice several <lift:...> tags. When a user requests a page, lift will try to find it in your src/main/webapp folder. If the page has any <lift:...> tags, they'll get processed before the response is sent back to the user. The first such tag we see is <lift:surround>. This tells lift to surround the enclosed xhtml with the "default" template. Templates can be found in src/main/webapp/templates-hidden. The second such tag is a <lift:snippet> tag. This tag instructs lift to call the "helloWorld:howdy" snippet, and replace the <lift:snippet> tag with the results of the snippet call. Snippets can be found in src/main/scala/com/test/snippet. Let's take a look at the HelloWorld.scala snippet. HelloWorld is a class which defines one method, "howdy". All that howdy does is return some xhtml. This is the xhtml that will replace the <lift:snippet> tag before the whole page gets sent back to the user. Notice that Scala allows XML literals right in the syntax. It also allows arbitrary Scala expressions inside the XML when escaped by {} brackets. As you can imagine, embedding xhtml straight into your code can be very useful for web development.
Let's get rid of the HelloWorld snippet and replace it with our own. Make a new class in com.test.snippet called "Submission", and define a method "form":
class Submission { def form = { var url = "" var title = ""
<span> { S.text("URL", u => url = u) } { S.text("Title", t => title = t) } { S.submit("Submit", ignore => LinkStore ! AddLink(url, title)) } </span> } }
Phew! There's a lot going on in these few lines. Let's try to break it down piece by piece. We're taking full-advantage of Scala's support for XML in the syntax to send back an xhtml form. We're using {} brackets to escape the XML syntax and insert arbitrary Scala expressions. The first and second Scala expressions reference "S.text". This is a method that will return a text input field. The first argument to the method is the default text in the field. The second argument is a function that will be executed on the contents of the text input field when the form is submitted. Take a moment to let that sink in. So when the form gets submitted, the stuff in the url field will be assigned to the "url" variable and the stuff in the title field will be assigned to the "title" variable.
"But how?!", you might ask. After all, Submission's "form" method gets called in one request-response cycle, and the html form doesn't get submitted until the next request-response cycle! Well, this is part of lift's magic. Between requests, lift keeps around a closure that knows about the "url" variable and about the "title" variable. Even better, the closure knows what to do with these variables once the form submission comes in. It works almost like magic.
Which leaves us one last thing to analyze. As you might have guessed, "S.submit" returns a submit input field (a submit button). The first argument to "S.submit" is the label on the button. The second argument is a function to be called once the form is submitted. This function sends a message (using "!", a method defined on Actors) to the LinkStore, telling it that we want to add a new link.
Now let's go back to index.html and change the "helloWorld:howdy" snippet to a "submission:form" snippet, like so:
Notice that we added a "form" attribute to let lift know that this snippet should be rendered as a POST form.
Reload your page and you should now see two form fields and a submission button. Entering information and pressing submit doesn't seem to do anything, but if we add a "Console.println" to LinkStore we'll notice that it is indeed receiving and storing links.
Now that we have links, how do we share them with the world? Something needs to be responsible for showing these links to our visitors and updating them whenever necessary. This sounds like just the job for lift's CometActor. CometActors know how to render themselves onto an xhtml page. They are also long-lived; a visitor can navigate away from the page and come back to find the same CometActor servicing his requests. Since they're long-lived, they can interact asynchronously with the visitor, outside of the normal http request/response cycle. We'll use these capabilities to make "live" updates to the page a visitor is viewing, without the visitor having to refresh the page. Let's get cranking. Add a new "com.test.comet" package, and in it define a new LinkActor class:
Let's start with the easy stuff. The "localSetup" method is called when the CometActor is created. This method sends a message to LinkStore (to make sure it gets added as a listener) and waits for a reply. The reply will contain the initial list of top links, which we store in the "topLinks" variable. The "localShutdown" method is called when the CometActor gets retired. This just cleans up and makes sure we're no longer listening to the LinkStore.
The "render" method does most of the interest work. This is how the CometActor renders itself to xhtml. It's going to create some xhtml with an ordered list of links. The links themselves get rendered by the inner "linkView" method. This method will render the link with the appropriate title, as well as showing the score beside the link, and "[up]" and "[down]" links to vote the story up or down. The "S.a" method takes two parameters, and returns the xhtml code for an anchor tag (link). The first parameter is the code that will be executed when the link is pressed. This code sends a message to the LinkStore, telling it whether the vote was an up-vote or a down-vote. (The "Noop" at the end of the block is just to let Scala know that this is indeed a JsCmd block that is safe to send to the browser.) The second parameter is an xhtml node that will be wrapped inside the anchor tag. In this case, it's just a simple text node that indicates whether the vote is up or down. With these parameters, lift creates an anchor tag that, when clicked, will send an AJAX request to the server to execute the provided code. Neat stuff.
Finally, the "lowPriority" method is where we listen for updates from the LinkStore. As you might imagine, CometActors have three similar methods: "lowPriority", "mediumPriority", and "highPriority". The only differences are the order in which they get applied. We're not doing anything too complicated with CometActors here, so "lowPriority" will work fine for our purposes. Whenever we get an UpdateLinks message from the LinkStore, we want to update our local copy of the links. We also call "reRender", which pushes the latest result of "render" to the page containing the corresponding <lift:comet> tag for this CometActor.
The last thing we have to do is place the <lift:comet> tag on a page. This will render the CometActor we've just created to that page, and will listen to the CometActor for updates. Let's go back to index.html and add the following right below our form submission:
Now you should have a site that functions exactly like the site in the screencast. If you open two different browsers, or two different windows in the same browser, actions taken in one browser window will be automatically reflected in the second browser window.
This introduction barely touches the full power of lift. We didn't really explore lift's Sitemap, ORM Mapper classes, extensive type-safety, semantic models, security-by-default, or advanced templating system. Hopefully, however, this gives you a taste of web development with lift, and showcases just one of lift's many features: advanced support for Comet-style web development.
This code borrows heavily from Steve Jenson's DynamicBlog, a part of the "hellolift" example project. Check it out at the lift source tree (http://liftweb.googlecode.com/svn/trunk/). Thanks to David Bernard for his help with syntax highlighting and with his feedback on a draft version of this blog post. And many, many thanks to David Pollak for his feedback on this blog post, but most of all for making such an awesome web framework.
I was a bit more than a year ago that I stumbled across Scala.
I had been doing Ruby and Rails for 18 months and Java for 10 years before I found Scala.
I was looking for a language that had the strengths of both Java and Ruby and I found them in Scala. I have been happy with the language and the community ever since.
Scala's goodness comes in many forms. Some practical (XML as part of the language syntax, runs on the JVM and has 100% compatibility with Java libraries), some geeky (Scala's type system is powerful and learning to program with primarily immutable data types is an excellent thought-challenge), and esoteric (Scala has an implementation of Erlang's Actors that's pretty spectacular.)
After coding in Scala for year, I find it very difficult to code in Ruby and almost impossible to code in Java. Scala has spoiled me on a bunch of different vectors.
Scala has a command-line interpreter. I can type lines of Scala, have them run... just like IRB in Ruby. That makes exploring a new API much, much easier. For example, I was writing some Crypto stuff the other day (in Java). I was able to check out the Java crypto stuff, run simple examples, etc. from the Scala command line. Once I was satisfied with the code, I ported it to Java and ran it. It's a lot easier than a "make changes to code, run the new program, see what it did" cycle with Java.
Scala's got XML right in the language. I was doing some SOAP coding recently. I captured the wire-level of some existing SOAP calls, copied the XML into my Scala code, and I had a running SOAP client in about 30 minutes. Some of the folks who were doing the same coding task in Java didn't even have all the import statements defined in by the time I had my code running.
Scala allows passing of functions and storing functions in Hashes, etc. It's like having amazingly light weight anonymous inner classes all over your code. In reality, the Scala compiler is creating a bunch of anonymous inner classes, but your code isn't cluttered with all the class definition stuff... your code is a simple statement that looks and feels like it's part of the current method. From a "picking your code up standpoint" it's much easier to understand what you did if your eye sees the substance rather than the cruft that is anonymous class definition.
You can code Scala just like you code Java. All the Java constructs are there (except the c-style for loop, but you'll never miss it.) You can connect to your Java classes and Java libraries from Scala. You can subclass Java classes, implement Java methods and your Scala code looks just like Java code to the other libraries. It's very simple to stick your toe in the Scala water and see if you like the temperature. Also, Scala code runs as fast as Java code so you're not sacrificing performance for language value.
Scala's traits and type system allow for type-safe, compiler checked meta-style programming. No, it's not changing the behavior of classes at runtime, but it is the ability to add complex functionality to classes simply by mixing new methods in. It's far more powerful than Ruby's mixin mechanism and the compiler takes care of making sure things don't get broken. An example of this is adding "user" functionality to an OR mapped class (first name, last name, email, password, etc.) In Ruby, this would be done with acts_as_xxx, in Scala this is done with class Foo extends Mapper with ProtoUser. And, yes, you can, at compile time, add methods to existing classes, even String.
So... what about lift?
One of the things that drove me to search for a new language after doing Ruby was the multi-fold needs for performance, type safety, and integration with Java libraries including Lucene.
I found Scala, but there were no web frameworks for Scala. Sure, I could have coded in Wicket and Hibernate using Scala, but then I would have lost a bunch of the Scala benefits. So, I sat down to write my own web framework. I started with a list of requirements and started coding.
I initially built lift "for me." Later, I started building lift for a multi-person team that I was part of.
Finally, the lift community developed a life of its own and people started using lift for real projects. There are currently 300+ people in the lift community, 5 active committers, and a bunch of active projects being built on lift (including Much4).
There are some amazing people in the lift community... people who know so much more than I do about so many different things. There's great give and take on the lift mailing list.
Most importantly, we're moving lift towards being a 1.0 product... a product that you can build a commercial application on top of. This means being developer friendly, having good documentation, having a decent tool chain.
So... what's so cool about lift?
It's got the code efficiency of Rails -- a few lines gets you a lot of stuff.
It's got the designer friendliness of Wicket.
It's got the statefulness of Wicket and Seaside.
Plus, lift is the best way to write AJAX and Comet applications. With a dozen lines, you can put a dynamically updating clock in your application. You can add chat with 50 lines. All this is possible because of Scala's Actors and the way lift abstracts away the HTTP request/response cycle.
Anyway... stay tuned to the Scala Blogs to see exciting developments in Scala and lift brought to you by some of the coolest people in the Scala and lift communities.