trevmex's tumblings

JavaScripter, Rubyist, Functional Programmer, Agile Practitioner.

Scala Lift

Philly Lambda October 2010 Talk (two)

David Pollak, author of Beginning Scala

Lift is a web framework written in Scala, but it is different than other frameworks. It is NOT MVC! It is designed for rich internet applications.

Scala is an OO language with powerful constructs.

It runs on the JVM, and you can use all your Java classes, and you can use all Scala classes in Java. They are fully interchangeable.

Scala code runs at native Scala speeds.

Scala also has a command line interpreter with tab completion.

Scala is a typed language, unlike Ruby, but it is smart with typecasting. Like ML, it will understand what your type is for inference.

Scala has built-in immutable data structures like lists and vectors.

Everything in Scala is an object (just like Ruby! Hooray!)

Therefore:

1 + 1
// is the same as
1.+(1)
// which equals Int = 2
// A simple class to dup a string 3 times.
class Foo(v: String) {def +(i: Int) = v * 3}
val f = new Foo("Hello ") f + 3 // => String = Hello Hello Hello
Vector(1,2,3).map(_.toString) // makes a vector of Strings
Vector(1,2,3).map(_.toDouble) // makes a vector of Doubles

def makeItADouble(i: Int) = i.toDouble
Vector(1,2,3).map(makeItADouble) // makes a vector of Doubles

Functions close over local scope, and we can reference everything over the local scope.

var x = 0
Vector(1,2,3).map{a => x += a; a + 10} // makes Vector(11, 12, 13)
x // becomes Int = 6

A var is a variable, a val in immutable.

val m = Map(1 -> 2, 3 -> 4, 5 -> "Hello") // Makes a Map[Int, Any]

m.get(3) // gets Option[Any] = Some(4)
m.get(3).map(_.toString) // gets Option[java.lang.String] = Some(4)
m.get(66) // gets Option[Any] = None (since it is anything that doesn't exist.)
m.get(66).map(_.toString) // gets Option[java.lang.String] = None (Now it is a string that doesn't exist.)
m.map(a => a._1) // Gets a list of the keys (List(1, 3, 5))
m.map(a => a._1 * 4 -> a._2) // Gets a map. Scala knows that THIS is a map, not a list, like the above example.

There is a REPL, but it is still a compiled language.

The Lift Framework

(we will be creating a chat app)

Lift gives you menus for free.

Security is enforced. With every Lift app, you get security for free, access controls are enabled by default.

Lift has authentication and authorization hooked in from the start. You do not have code auth work yourself for basic web app.

All of your dynamic page creation is done by transforming XML to XML.

The chat server view:

<lift:surround with="default" at="content">
  <lift:comet type="Chat">
    <ul>
      <chat:line><li><chat:message/></li></chat:line
    </ul>
  </lift:comet>

  <div>     <lift:form>       <lift:ChatInput/>       <input type="submit" value="Chat" />     </lift:form>   </div> </lift:surround>

Comet is Lift’s version of a library to make AJAX calls. It can do long pooling to the Internet, as well as all the complex things that a live HTTP connection needs to do to stay alive correctly.

Lift takes and makes comet easy. Lift takes and makes comet possible. Lift abstracts out all the messiness of comet and does what you want it to do without worrying about the details too much. All you have to think about is: push changes here, get changes there. That it is!

An object is a singleton within its scope of reference in Scala, unlike a Java static.

Objects can have traits that are like mixins in Ruby.

Vectors are immutable, and have O(1) append and remove from head and end.

The Stairway Scala book is a great resource of information on Scala.

The chat server guts:

package code.comet

import net.liftweb._ import http._ import actor._
import scala.xml.NodeSeq
object ChatServer extends LiftActor with ListenerManager {   private var messages = Vector("Welcome")
  def createUpdate = messages
  override def lowPriority = {     cases: String =>       messages = messages :+ s     updateListeners()   } }
class Chat extends CometActor with CometListener {   private var messages: Vector[String] = Vector.empty
def registerWith = ChatServer
override def lowPriority = {    case m: Vector[String] =>      messages = m    reRender() }
def render = bind("chat", "line" -> line _)
def line(html: NodeSeq): NodeSeq =    messages.flatMap(m =>    bind("chat", html, "message" -> m)) }

The chat input file:

package code.snippet
import code.comet._ import net.liftweb._ import http._ import js._ import JsCmds._ import JE._ import util._ import Helpers._
object ChatInput {   def render = SHtml.text("", s => {     ChatServer ! s     SetValById()"chatty", "")   }) % ("id" -> "chatty") }

The above compiles to a working chat client by running it with sbt. (warning, there may be typos in my code. I was copying live)

Scala has no preprocessor, so you have to import all the libraries you need in every file. Twitter has solved this by preprocessing Scala code with ERB.

Lift takes care a lot of the drudgery of writing web apps. With a small amount of code you can do a lot of things. This is pretty advanced.

Lift supports parallel threads as well as lazy loading of parts of the page.

Lift has a Wizard object like JBoss Seam that takes care of multi-page input forms with all the magic (like back arrows, etc.) working as you would expect.

Lift apps are small but pretty powerful. It is a lot more consist than Rails code by giving you more logical defaults.

One of the most interesting things is that it is secure by default. Pretty cool. Oh, and foursquare uses it. Neat, huh?

Lift is:

  • Dynamic
  • Secure
  • Scalable

You will invest more time developing up front with Lift, but it will pay off down the road in utility.

What is an Actor? Check out the Concepts and Structures on Programming Languages book based off the Mozart language.

(Sorry if I missed some stuff, Toby and David got into some crazy stuff that is way over my little brain, but I hope that the notes I have taken are useful some of you!)

What is a good Scala book? Read the Staircase book (it is the Pickaxe book for Scala), and then go read Beginning Scala by our speaker, David.

Thanks to David for a great talk!

Notes

  1. trevmex posted this