Monday, October 22, 2007

Fun With Scala: Things I'm Learning From Lift #2

Thanks to astute reader Ken (Author's Note: I have a reader! An astute one! Who knew?!), I learned something about a feature I was bragging about in my last post; namely, the ability to import members of a class. As it turns out, not only is this feature present in Java 5 -- see the documentation for static imports -- the Scala version of it is pretty much equivalent.

Ken points out that my example of lift importing the members of the net.liftweb.util.Helpers "class" maps exactly to the corresponding Java import. I waved my hands around the fact that Helpers is actually an object, which is, simultaneously and at the same time, Scala's way of denoting a singleton and providing static members (all of the members of an object are effectively static). But it turns out that the import syntax I was bragging about works precisely because Helpers is an object and not a class.

Here's some lame, contrived, forced-example, somewhat-minimal Scala code to demonstrate:

Mixee.scala

package bogus;

class Mixee {
def weird: String = {"Weird Al!"}
def twentySeven: String = {"27!"}
}


Mixer.scala

package bogus;

import Mixee._;

object Mixer {
def main(args: Array[String]): Unit = { Console.println(weird); Console.println(twentySeven) }
}

As described here, Mixer.scala will refuse to compile, with the error: "not found: value Mixee". This is because Mixee is defined as a class. Change class to object and it compiles (and runs) just fine.

Bonus Discovery: While researching this, I also learned that Eclipse with the Scala plugin is not as smart as it should be about building my bogus project. If I start with a clean compile (i.e., defining Mixee as an object), Eclipse is happy. If I then change the definition of Mixee from object to class, the error doesn't show up until I force a rebuild by selecting Project -> Clean... If I then change class back to object, the error goes away without my forcing the rebuild.

Anyone got a line on that? Ken? Anyone?

Anyway, just for the record, my purpose with these posts is not to bury Java, but to praise Scala and learn how it's different. I'll leave the determination of whether Scala is "better" than Java up to you, my readers. Both of you (hi, Mom!). ;-)

Tuesday, October 16, 2007

Fun With Scala: Things I'm Learning From Lift #1

So I'm starting somewhere around the very beginning with the Liftweb framework: LiftServlet.scala, which is in the net.liftweb.http package. This looks like Lift's answer to a Rails controller, or a Struts Action (Author's Note: probably with some caveats that I haven't found yet; (pleasant) comments welcome if I'm wrong about this).

Fun Thing #1: The very first import is
import javax.servlet.http.{HttpServlet, HttpServletRequest , 
HttpServletResponse, HttpSession}

How's that for interoperability with Java? I haven't gotten that far yet, but this tells me that whatever Lift uses for its request/response implementation is going to conform to the usual Java interfaces. And how do you like the syntax for this style of import? I like it a lot, because it lets you do the equivalent of:
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
...et cetera...

...on a single line (it's a single line in the original source; I've split it here for friendlier rendering). Without resorting to importing everything in the http package with a wildcard. This way you get to see exactly what you need. Yeah, I know a good Java IDE will manage the imports for you, so it's not as much of a pain as it used to be, but I like the compactness of this syntax. As it happens, the current version of the Scala plugin for Eclipse doesn't have the equivalent of "Organize Imports", so this syntax is definitely a boon.

Fun Thing #2: There's a syntax for importing not just classes, but members of a class. Like so:
import net.liftweb.util.Helpers._

This basically says "make everything in the Helpers class (actually it's a singleton object, but think of it as a class for now) available to this class without my having to qualify it with 'Helpers.' all the time".

For example, there's a bit of code in LiftServlet that goes like this:
val md = parseInternetDate(mod)

This makes it appear that parseInternetDate() is defined in the LiftServlet class. But it's not. It's defined in Helpers. If you're used to modules/mixins in Ruby, this should seem very familiar to you. If not, now might be a good time to get used to them, because they're way cool.

Fun Thing #3: No, the lack of semicolons at the end of the code samples is not a typo. The Semicolon is Dead! Long Live the Semicolon! No, scratch that -- Long Live Scala!

Sunday, October 14, 2007

Fun With Scala: Liftweb Getting Started

Job one: checking out and Eclipsify-ing lift.

The instructions at the CircleShare lift blog are still current up to a point, at least as far as the prerequisites are concerned. I'm running from trunk, so my source code checkout was a little different:
svn co http://liftweb.googlecode.com/svn/liftweb

After that, the available instructions need a little (ahem) updating.

For a quick look at the kinds of things you can do with lift, run mvn install in the liftweb (top level) directory to build everything. When that's done, cd sites/project_name, where project_name is one of example, hellolift, or skittr. From there, run mvn jetty:run to start a Jetty web server running on some port on localhost. At this writing, example and hellolift run on port 8888, while skittr runs on 8889. Don't ask me why.

You can also mvn install individual projects if you want, but I don't see any harm in building them all in one shot.

To Eclipsify, make sure you have the Scala Development Tools plugin installed, then run mvn eclipse:eclipse in the project you want to be able to work with in Eclipse. You can do this for the lift source code itself (under the liftweb/lift subdirectory), or any of the example projects (liftweb/sites/project_name where project_name is as above).

Happy Lifting!

Fun With Scala: Liftweb

In my last post, I poked some serious fun at a bunch of mainstream languages (actually, their Internet communities), but left Scala pretty much alone. I chose Ruby and Java as my main characters because those are the languages I read the most about, and whose pundits' positions I felt like I could parody most accurately.

I've been interested in Scala since I first came across it, but I haven't really had to time to do much with it. I like its functional leanings, and I am intrigued by its ability to run on the JVM and interoperate seamlessly with existing Java libraries. Although when I say "interoperate", I have to acknowledge that it's a one-way street, as far as I know. Scala code can certainly invoke methods on Java classes. I have yet to figure out how to make the reverse happen (not that I've tried very hard). If I can, I will definitely try to make use of that capability.

So I've decided to do something real with Scala, to force myself to get to know it better. I've chosen Liftweb as my target project, largely because it's there and it's the only substantive chunk of Scala code I've found. You may have read about its claims to be able to implement a full-on Twitter clone in less than 1000 lines of code, with the capability of handling one million or more users on a single commodity PC.

Attention has been paid.

Wednesday, October 03, 2007

The Last Language War / Language Trolling Post You'll Ever Need To Read (Hopefully)

Moderator: Greetings, and welcome to the First-And-Possibly-Last-Ever Pan-Computer-Programming-Language Conference (FAPLEPCPLC). I am joined on stage tonight by many distinguished, high-profile computer programming languages. Each is highly regarded by its devotees, and I for one look forward to hearing what each has to say.

Ruby (grabbing the microphone): Um so yeah I'd just like to kick this bad boy off by saying that THE REST OF YOU SUCK A**!!! Yeah, I said it! The A-word! A**! Oh yeah! Boom, baby! Woo! Ruby FTW!

Java (rolling its eyes): Oh, real mature. I, on the other hand, would like to state that I have important work to get done in the Enterprise, so let's not waste everyone's time. I suggest we proceed using the Computer Programming Languages Discussion Pattern as implemented in JSR-6942, the Java™ Absolutely Void-of-Acronyms Talking About Languages at Konferences (JAVATALK™ which by the way is not an acronym for anything) specification.

Ruby: Dude! I just wrote a full working clone of Google while you were giving your riveting little speech there!

Moderator: Oh, bravo, Ruby! I'd like to see that. Where is it deployed?

Ruby: Umm....

Lisp: In the beginning, there was the Lambda. And John McCarthy saw the Lambda. And John McCarthy saw that the Lambda was very good.

Ruby (rolling its eyes): Here we go...

Lisp: And John McCarthy spake, and lo! the tongue he spake was sexp...

Ruby: He said sex! Heeheeheeheehee!

Erlang: If I may, I've been running some ideas by the other panelists, all at the same time of course, not that that's any big deal...

Ruby (rolling its eyes): And here we go with the concurrency...

Java: Gosh darn it, Ruby! There's no need to pooh-pooh everything someone else says, eh?

Ruby: He said poo-poo! Heeheeheeheehee!

Java: Ruby, I swear, one of these days...

Ruby: Hey, don't give me any of your static! Heeheeheeheehee! See what I did there?! "Static"?! 'Cause I'm so dynamic?! GET IT?!!! DAMN, where's my BAWLS Guarana...?

Ruby (seconds later): I said balls! Heeheeheeheehee!

C#: Developers! Developers! Developers! Developers!

Erlang: ...I'd share my results with you, but it's going to take a while to retrieve them from the filesystem...

COBOL: keels over, only to be frantically revived by about three banks.

Basic: Actually, I have a question for Ruby...

Haskell: Me too...

ML: Hey, Ruby, what's your answer to...

Ruby: Hey, hey, hey now! Not too many at a [segfault]

Java: smiles

bash: kill -9 self

The Lambda Calculus: Actually, if we could all just take a moment to reflect on the implications of the Church-Turing thesis...

Everyone Else: Oh, SHUT UP!!!!!!

Scala: says nothing, but sits quietly observing, taking notes, and learning a lot.

Moderator: Well, I think it's about time to bring some closure to this, um, lively...discussion...

Java (sharply): Hey! We're working on it!

Lisp: ))))))))))))))))))))))

Java 1, Intuition 0

Pop quiz: If you were given the following snippet of code:
"".split("\\s");
...what would you expect the result to be?

If it helps, the contract for String.split() is that it takes a regular expression (in this case \s means "anything that could reasonably be considered whitespace, like spaces, tabs, et cetera"), and returns a String[].

My intuition was that it would return an empty String[]. (Author's Note: which would have been better than a null, but even that's not what I got.)

I mean think about it: what does it mean to split the empty string, on any character? The empty string has length 0, so what can you split it into? Two strings of length 0? But then you could do that ad infinitum, which would be silly.

So what Java actually does is return an array with one string: the empty string, or one string of length 0. Which implies that Java thinks the beginning of a string -- represented by the regex \A, or ^ if you know the string you're regex-ing doesn't contain newlines -- is significant, but the end of a string (\Z or $) is "whitespace". I guess you could make a case for this making sense, but it doesn't match up with my intuition.

What do you think?