de.velopmind | The Det about Programming

July 10, 2010

Scripting with Scala vs. Groovy

Filed under: Experiences, Groovy, Scala — de.velopmind @ 11:21 pm

Last week I decided to challenge Scala’s downscalability by trying to replace a Groovy script with a Scala pendant.

In this article you will read about this little experiment and a comparision of the Scala result with the Groovy predecessor.

But first some background about the script:

Some time ago my company introduced a new spam notification system.  When it thinks that a mail contains spam, it keeps it in quarantine and once or twice a day sends an email to the recipient (me) reporting all the kept mails, together with an intranet web link for each  to release it.

Here you see an example of such a mail (note: I have my mails displayed in plain text format):

Unfortunately the spam filter holds back most of the mails I receive from mailing lists like groovy-user, scala-user, log4j and others. Each morning I would have to open such a mail and for each kept item click on a link, wait for the browser result, close the page, go back to outlook, click the next link, and so on and so on.  Sure, this is very annoying, but a request to our IT personell did not solve the problem as it seems to be impossible to administer the white list in a way to generally let mailing list stuff through. It only works on a real sender address basis.

Well, I would not be a programmer if I would not solve the problem myself.

So I opened a Groovy console and quickly hacked a little script which let me automate the calls to the URL.

Let’s look at it in detail.

When started, the script opens a small window with a text box to insert the spam guard mail text.

On pressing the “convert” button,  a new frame opens with a line for each kept mail including a check box which is pre-selected:

On pressing the action button in this frame, the script  iterates through each line and calls the corresponding URL (well, only if the checkbox is still checked). You can follow the progress by watching the checkboxes on the right, where each processed line is marked.

So with a few clicks even a good bunch of kept mails is released automatically.

As I said, the source code is a very simple hack which I threw together in round about twenty minutes, including some book/web lookups as I have never really written a Groovy SwingBuilder based GUI before, and calling aURL was also not in my recordings.

Well, trying to rewrite this thing in Scala did not went as fast, and the result is not hundred percent the same.  But let us have a detailed look at both sources side-by-side.

I started at the beginning and developed top-down. So the first thing to look at is the method that starts the input window with the text area.

Here is how this method reads in Groovy:

def inputWindow() {
    inp = new SwingBuilder()
    frame = inp.frame(title:"Insert mailtext", size:[400,400],
                      defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) {
             panel(layout: new BorderLayout()) {
                scrollPane() {
                 editorPane(id:"mail", maximumSize: [300, 300],
                            minimumSize: [300,300], preferredSize: [300,300],
                            constraints:BorderLayout.CENTER)
                }
                button("convert", actionPerformed: {selectWindow(inp.mail.text) },
                       constraints:BorderLayout.SOUTH )
             }
    }
    frame.visible = true
}

First step is to create a SwingBuilder, which now makes it very simple to create a frame, a panel with a scrollpane containing an editor pane and a button on it and start this form. All easily done and readable due to the clear structure of SwingBuilder containment structure.

To make this code runnable we need some imports first, and here they are:

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

Let’s see how Scala handles this.

First we need some imports too…

import scala.swing._
import scala.swing.Swing._

… and here’s the method:

    def inputWindow() = {
       new MainFrame {
           val mailPane = new EditorPane() { maximumSize = (300, 300);
                                             minimumSize = (300, 300);
                                             preferredSize = (300,300) }

           title = "Insert mailtext"
           size  = (400,400)
           contents = new BorderPanel {
                 import BorderPanel._
                 add( new ScrollPane ( mailPane ), Position.Center )
                 add( Button("convert"){ selectWindow(mailPane.text) } ,Position.South )
           }
       }
    }

Well, all in all this structure is as concise and as easily readable as the Groovy one. But there are some differences I want to mention here.

The first difference we see immediately is, that the mailPane is created first and stored in a dedicated variable. This is not only for code layout purposes, but necessary, as it has to be referrable later in the button’s action to get the pasted text.
In Groovy this is achieved by accessing the SwingBuilder instance, which also serves as a repository for the created components.

The next difference is, that in Scala we often create new instances with ‘new’, indeed creating anonymous subclasses this way, while in Groovy all is done by applying the builder syntax as a DSL and let the builder maintain the instance creation under the hood.  In the above code the Button is special. Instead of a ‘new’ call we see a shortcut. The button is created by applying the companion object of class Button and providing that with a code block to be executed on click.

And this was the first confusing thing for me: Some components provide companion objects, but not all. And which provide an apply method as shortcut is not clear.  One has to consult the scaladoc, and even that is often too rudimentary. In the end this shortcut option seems to be special for Button.

Another confusing thing is the way to add components to a container. Sometimes ‘add’ seemed the right way, sometimes ‘contents+=’ . But the latter does not work in a frame, where it is merely ‘contents=’ . The documentation is sparse. The Swing chapter in Programming in Scala did not answer all my questions and finding documentation on the web took me some time. After stumbling over possibly outdated, too short or academic stuff, I finally returned to  this link . It is not really a tutorial (and that’s why I stepped over it first), but an at least somewhat helpful introduction to the concepts,  and eventually it took me forward.

Ok so far about my docu experience. What now happens when clicking the button? Or better: what does method ‘selectWindow’ do?

Here I want to turn things and go bottom up first. At the beginning of selectWindow the text from the editorPane is converted into a collection of rows, containing the data and the checkbox widgets.

Let’s have a look at this job first:

Here’s the original Groovy version of the Row class:

class Row {
  def selectbox
  def date
  def address
  def title
  def url
  def donebox
}

You see, this is very concise. But Scala is close behind with its clase class construct.

    case class Row ( selectbox:CheckBox,
                     date:String,
                     address:String,
                     title:String,
                     url:String,
                     donebox:CheckBox)

This one is also a bit more helpful, as it provides the types. I could have done that in Groovy too,but due to the scriptic nature of the problem it seemed natural not to bother with such trivia. This statement will give just enough potential for long debates, I think.

But now for the conversion of a ‘text’ into a bunch of such Rows.

Again first the Groovy version:

def convert(inputtext, builder) {
    result = []
    inputtext.split("\n").each{ line ->
        matcher = line.trim() =~ /(2010\S*)\s*(\S*)\s*(.*?)\b*(Anfordern|Request) \(HTTP\)\b*.*<(.*)>.*/
        if (matcher.matches())
            result << new Row(selectbox: builder.checkBox(selected:true),
                                         title:matcher[0][3], url:matcher[0][5],
                                         date:matcher[0][1], address:matcher[0][2],
                                         donebox: builder.checkBox(selected:false))
                   // matcher[0]  [1]->date [2]->address [3]->subject [4]->wordgroup [5]->URL
    }
    result
}

And immediately the Scala solution:

    def convert(inputtext:String):List[Row] = {
        val regex = """(2010\S*)\s*(\S*)\s*(.*?)\b*(Anfordern|Request) \(HTTP\)\b*.*&lt;(.*)&gt;.*""".r
        val result = for( regex(date, address, subject, label, link) &lt;- regex findAllIn inputtext )
                         yield  new Row(selectbox = new CheckBox { selected = true },
                                        title = subject, url = link,
                                        date = date, address = address,
                                        donebox =  new CheckBox())
        return result.toList
    }

What’s notable here is that in Groovy you are in contact with such details as the matcher and its array representation, what leads to the necessity to note in a comment what index is what.
In Scala on the other hand you work on a more abstract, more declarative level, keeping such details as the match handling and the collection maintenance under the hood.

The resulting Row list of the above method is now used to construct the second frame (Groovy):

def selectWindow(inputtext) {
    job = new SwingBuilder()
    content = convert(inputtext, job)
    frame = job.frame(title:"Uncheck real spam mail", size:[800,800] ) {
         panel(layout: new BorderLayout()) {
             scrollPane(constraints:BorderLayout.CENTER) {
               panel() {
                 tableLayout {
                   content.each { row ->
                     tr {
                        td { widget(row.selectbox) }
                        td { label(text: row.title,
                                   toolTipText: "${row.date} ${row.address} ${row.title}") }
                        td { widget(row.donebox) }
                     }
                   }

                 }
               }
             }
             panel(constraints:BorderLayout.SOUTH) {
                   button("action", id: "action", actionPerformed: {process(content, job)} )
                   button("close",  id: "close",  actionPerformed: {frame.dispose()}, enabled:false)
             }
         }
    }
   frame.visible = true
}

Here we see one of Groovy’s strengths: The table layout, which lets you declare the positioning like a table in html. Very easy and handy.  Beside that, take a look at how the buttons and their actions are declared in one expression.

Now the Scala pendant:

    def selectWindow(inputtext:String) {
        val rows = convert(inputtext)
        val frame = new Frame {
           val doit = new Button("action")
           val closeB = new Button("close") { enabled = false } 

           val listPane = new BoxPanel(Orientation.Vertical) {
                              rows.foreach { row =>
                                 contents += new BoxPanel(Orientation.Horizontal) {
                                                   contents += row.selectbox
                                                   contents += new Label(row.title) {
                                                                   tooltip = row.date+" "+row.address+" "+row.title }
                                                   contents += row.donebox
                                             }
                              }
                          }
           title = "Uncheck real spam mail"
           size  = (800,800)
           contents = new BorderPanel {
                 import BorderPanel._
                 add( new ScrollPane ( listPane ), Position.Center )
                 add( new FlowPanel {
                         contents += doit
                         contents += closeB
                      },Position.South )
           }

           listenTo( doit )
           listenTo( closeB )
           reactions += {
              case ButtonClicked(`doit`)   => process(rows, doit, closeB)
              case ButtonClicked(`closeB`) => this.dispose()
           }
       }
       frame.pack
       frame.visible = true
    }

Again things are done a bit different. First, we again notice the declaration of vals for components to refer to them later (doit and closeB). Then, with listenTo(…) and reactions+= we see the reactive way of declaring actions in Scala swing.

What is important here is that Scala swing does not provide an easy to use container layout, like Groovy’s table layout. The options would have been to introduce third party things or to fiddle with a GridBag layout or such things. But to shorten the development time (which already was longer than expected due to the need to search for documentation), I decided to simply use the BoxPanel container.  The result is a bit ugly, but is usable.

We come to the “action” button now, and to method “process” which implements its action. This is now the central purpose of this whole script: For each row call the URL and check the result box.

That is how it looks in Groovy:

def process(content, builder) {
   builder.action.enabled = false
   builder.doOutside {
     content.each { row ->
       if (row.selectbox.selected) {
           def result = callURL(row.url);
           builder.doLater { row.donebox.selected = result }
       }
     }
     builder.doLater { builder.close.enabled = true }
   }
}

We see here another feature of the Groovy Swing Builder: A simple way to let code run in another thread with doOutside, and then push things back on the EventDispatchThread with doLater. This way the GUI is visibly updated for each row as it is processed, and in the end the close button is enabled.

Scala does the same this way:

    def process(content:List[Row], action:Button, close:Button) {
        action.enabled = false
        actor {
            content.foreach { row =>
               if (row.selectbox.selected) {
                   val result = callURL(row.url);
                   Swing.onEDT { row.donebox.selected = result }
               }
            }
            Swing.onEDT { close.enabled = true }
        }
    }

It resembles exactly the same structure. Instead of doLater we call Swing.onEDT. Most notably is the way to push code onto another thread. Coming from Java Swing and looking at the Groovy way to call a builder method, I first looked for a method on Swing as opposite to onEDT. Then I looked for a SwingWorker class, which indeed exists but is not documented and seems even to have no meaningful implementation(?). In the end I slapped on my head and thought “why, it’s Scala”. And indeed the natural way to run stuff on a new thread is the “actor” method. Nothing Swing specific here.

The method “callURL” now is the next step to get things done, supported by a method named “checkResult”. In Groovy this is:

def callURL(urlstring) {
    try {  def url = new URL(urlstring)
           return checkResult(url.text)
    } catch (Exception e) {
           println "Exception when Accessing URL: "+e.message
           return false
    }
}

def checkResult(content) {
    if (content =~ /Ihre Anfrage wurde verarbeitet/) {
        println "CONTENT OK"
        return true
    }
    else {
        println content
        return false
    }
}

Interesting to see that with new URL and url.text the call is done.

The Scala pendant:

    def callURL(urlstring:String):Boolean = {
        try {
           val txt:String = Source.fromURL(urlstring).getLines().mkString
           return checkResult(txt)
        } catch {
          case e:Exception =>  println ("Exception when Accessing URL: "+e.getMessage())
                                          return false
        }
    }

    def checkResult(content:String):Boolean = {
        val rgx = "Ihre Anfrage wurde verarbeitet".r
        rgx findFirstIn content match {
            case Some(x) => println ("CONTENT OK"); true
            case None    => println (content) ; false
        }
    }

Once again the structure is analogous to the Grooy one. The interesting difference here is the way to call the URL. Again it took some time to find the solution, as I first looked for what class URL might offer, but Scala simply uses the Java one. And I was led into the wrong direction by an old post which gave me the impression some time ago that object Source has to do with reading files. But after some googling I detected that I was wrong: Source is the way to go, as it is an abstraction for textual data sources, not for source files or source code.
Also the getLines() and mkString needed a bit of exploration, but in the end I got the feeling that I should have known that. I had seen this before.

Well, that was the complete program in the two languages so far. What remains is, how it is started. And here we have a big difference.

The Groovy script was … well, a script. That means, adding a line which calls the topmost method “inputWindow()” and I had a runnable script which could simply be started with e.g. “groovy releaseSpam.groovy”.

The Scala way was not as simple. Although the Scala Swing API was used to instanciate and control widgets, we miss the infrastructure so far, which we get by Groovy SwingBuilder.
To gain this, the Scala code shown so far must be wrapped inside an object which extends SimpleSwingApplication and defines a method “top” which returns the main frame.

Here is the structure:

object Main extends SimpleSwingApplication {
      // .... the code shown so far

   def top = inputWindow()
}

Normally we can now add a line at the end calling the main method like:
Main.main(Array(“”))
And run that as a script.

But that does not work together with Scala.swing and SimpleSwingApplication.
Trying to put the code in a file named “releaseSpam.scala” and call it with the scala command results in :

cmd.exe /c  scala releaseSpamMail-WIP.scala
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: Main$$anon$12$Main$
$anon$6$$anon$10
        at Main$$anon$12$Main$.inputWindow(releaseSpamMail-WIP.scala:125)
        at Main$$anon$12$Main$.top(releaseSpamMail-WIP.scala:139)
        at Main$$anon$12$Main$.top(releaseSpamMail-WIP.scala:13)
        at scala.swing.SimpleSwingApplication.startup(SimpleSwingApplication.scala:7)
        at scala.swing.SwingApplication$$anonfun$main$1.apply$mcV$sp(SwingApplication.scal
        ............

So the best way to run it is to compile it, jar it, and run the resulting jar with:
scala -cp .\releaseSpam.jar Main

At the of this article now let us talk about another aspect:  The way I programmed the scripts.

With Groovy it was a very fluent experience, as I used the GroovyConsole to continuously work in a edit-run loop and store the script when appropriate.

Scala has only the REPL, which is no adequate replacement.  I worked with Vim to get a comparable feeling, but after detecting that I cannot run code containing Swing as a script, it mutated to an edit-compile-run cycle. Well, this is also easily done out of Vim, so no real disadvantage.  But you need and external editor with good developer support to achieve that flow and that is a bit a pity.

Result:

So what is the result now?  Well, all in all Scala seems as well fit for scripting tasks as Groovy is. The code is concise and expressive and readable in both cases. But currently Groovy wins for this task, because of better documentation and/or more intuitive API,  because of Scala.swing  not including a simple layout for quick tasks, because of Scala.swing  not being runnable in a script, and because of the necessity to use an external development tool.

But if you are familiar with the API (which I am much more for the next task now), use a specific IDE tool anyway and don’t bother keeping the solution as a program instead of a script, Scala is indeed a good match. And improvements will come with further development efforts of the community, for that I am sure.

I hope you liked this little article.

Advertisements

4 Comments »

  1. I really like this article.

    When other articles compare Groovy and Scala just by theory, you show code!

    Amazing. I think why Scala doesn’t fare quite well here is due to usage of Swing. I think the result will be so different when comparing Groovy+Grails/Gaelyk vs. Scala+Lift/JSF i.e. on a Java EE context.

    Thanks for the useful article!

    Comment by Hendy Irawan — October 13, 2010 @ 9:25 pm

  2. Hmm I can’t just “notify on comments” so I have to comment again 😉

    Comment by Hendy Irawan — October 13, 2010 @ 9:26 pm

  3. Both suck here since swing sucks. Wrong example but right approach for comparing the two.

    Comment by ratthis — December 16, 2010 @ 8:50 am

  4. Really neat blog post.Really thank you! Will read on…

    Comment by Jaylon Shih — March 13, 2012 @ 7:06 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: