The point is missed

Museum of public mistakes and unfinished projects

Drying up widget creation

with 6 comments

I continue to be amazed how Scala lets me keep my code DRY (if I care to do it the tools are there, I just need to look for them). One of the reasons that Scala allows this more than Java is that Scala supports functional programming. One thing that makes Scala interesting is that Scala blends Functional Programming and Object Oriented programming. This is often overwhelming but it really keeps the tools you need close at hand.

To start with I had to be torn kicking and screaming from my beloved object orientation. I was told I suffer from the Stockholm syndrome which was quite a hilarious way to put it. Especially since I live in Stockholm and was immediately comforted by the same person with the words “I suffer from it too, I still love C++”. So I thought maybe leaving my comfort zone is not so bad?

Yesterday it payed off and I experienced a kind of flow that was new to me in Scala. I thought I’d share that experience here step by step. Don’t expect to be blown away by my Scala-skills, If you want to be impressed in that way there are other blogs :) What follows is a real world example of  things coming together into a moment of productiveness. I guess another real world example of applying Scala to a problem could not harm?

In a previous post I wrote about how to make a DSL for creating SWT-guis in Scala. My source of inspiration was Glimmer. One thing that is obviously lacking in that example is some interaction with other code (in any direction) so I set out to solve that. I have come up with a few different ways and one of the several ways, more on them in a different post, I would like to support is to observe one or several other objects from the GUI. That requires an update mechanism. Some way to tell the created GUI to update itself. I have that solved too but I want to zoom in on one interesting step in the solution. A refactoring. I have ended up with a lot of small snippets like this:

trait Labels {
    def label(setups:(Label => Unit)*)(parent:Composite) = {
        val label = new Label(parent, SWT.NONE)
        setups.foreach(setup => setup(label))
    }
 

    def progressBar(setups:(ProgressBar => Unit)*)(parent:Composite) = {
        val progress = new ProgressBar(parent, SWT.NONE)
        setups.foreach(setup => setup(progress))
    }
}

Basically, I can create a progress bar, a label and both of them can be manipulated with 0 or more setups. Before we continue, let’s rewrite the first of the methods in a more verbose way so that even I would have understood that method 3 months ago:

def label(setups:(Label => Unit)*):(Composite) => Unit = {
   def createWidget(parent:Composite):Unit = {
      val label = new Label(parent, SWT.NONE)
      setups.foreach(setup => setup(label))
   }
   createWidget
}

This is exactly the same as the first example but more verbose and explicit. The double parameter-lists is syntactic sugar in Scala to return a function. Once you get used to it’s easier to read IMO so I have adopted it. It should be pretty clear now that the evaluation will occur in two steps:

  1. provide a list of setups (functions that takes a label as their only argument). This step will return a function that takes a composite (the createWidget function).
  2. Interestingly enough the returned function is “charged” with the setups and they will be invoked in the setups.foreach part when the composite, parent is provided. Not before, not after.

Now to the problem I wanted to solve. There is obvious duplication between the two functions in the first code-listing. The most obvious duplication (as I saw it) was the setup part. Lets extract a function for setting up the label:

    def label(setups:(Label => Unit)*)(parent:Composite) = {
        val label = new Label(parent, SWT.NONE)
        performSetup(label, setups)
    }
    def performSetup(target:Label, setups:Seq[Label =>; Unit]) = { 
        setups.foreach(setup => setup(target)) 
    }

This step really did not gain us that much. One thing to notice is that we pass the variable argumet setups into a parameter of type Seq. So variable arguments are just sequences. There is not an awful lot less code and we can’t use the performSetup method for progress-bars. Lets fix that. If you look at the performSetup-function there is not anything specific to labels in that function. So what type should it be? It’s really not important as long as it’s the same type that the functions in setups take. You won’t get a more obvious case for generics, and a pretty basic flavour also. Lets change the label to a generic type:

    def performSetup[T](target:T, setups:Seq[T => Unit]) = { 
      setups.foreach(setup => setup(target)) 
    }

That was easy, now we can use the performSetup method in both the label and progressBar functions:

    def label(setups:(Label => Unit)*)(parent:Composite) = {
        val label = new Label(parent, SWT.NONE)
        performSetup(label, setups)
    }
    def progressBar(setups:(ProgressBar => Unit)*)(parent:Composite) = {
        val progress = new ProgressBar(parent, SWT.NONE)
        performSetup(progress, setups)
    }
    def performSetup[T](target:T, setups:Seq[T => Unit]) = { 
        setups.foreach(setup => setup(target)) 
    }
 

Ok, slightly better than what we started with but we still have obvious duplication. The only thing that really differ between the two functions (besides the names)is the creation of different widgets. If we could parameterize the creation of widgets we would have a reusable template. Lets try by copying and changing the label function. I will rename it to createWidget and then try to remove the label-specifics:

    def createWidget(setups:(Label =>; Unit)*)(parent:Composite) = {
        val label = new Label(parent, SWT.NONE)
        performSetup(label, setups)
    }
    def performSetup[T](target:T, setups:Seq[T => Unit]) = { setups.foreach(setup => setup(target)) }

So, we obviously have to remove the creation of the label. As a first step lets make a factory-function and insert it in the parameterList:

    def createWidget(factory:Composite =>Label)(setups:(Label => Unit)*)(parent:Composite) = {
        val label = factory(parent)
        performSetup(label, setups)
    }
    def performSetup[T](target:T, setups:Seq[T => Unit]) = { setups.foreach(setup => setup(target)) }

By inserting an extra set of parameters we have created:

  1. A function that takes a factory that creates lables that…
  2. returns a function that takes setups that… (note that at this point we have an equivalent function to our old label-function)
  3. returns a function that takes a composite…

We can now update our label function to step use 2 if we just have a factory. Time to bring out a new trick from the bag of tricks:

    def label = createWidget(new Label(_, SWT.NONE))_
    def createWidget(factory:Composite=>Label)(setups:(Label => Unit)*)(parent:Composite) = {
 val label = factory(parent)
 performSetup(label, setups)
 }
    def performSetup[T](target:T, setups:Seq[T => Unit]) = { setups.foreach(setup => setup(target)) }
 

Ehhhh, what happened? Well, at first the underscores in Scala are a bit confusing and above we use them in two places.
First there is an underscore in the Label’s constructor where we used to pass in parent. SWT.NONE is still where it used to be. What we have done is to leave the parent-parameter to be filled in later. If you think of it, a constructor is in essence a function that returns a new instance of some class. In the Label-case: (Composite, Int) => Label.

Pre fill the params part: new Label(_, SWT.NONE) and we have a (Composite) => Label which is exactly what we need for the first argument of our createWidget function.

The second _ is a placeholder for “the rest”, which is (setups:(Label => Unit)*)(parent:Composite).
That parameter-list should look familiar from our first version of the label-function.
Now we want to use our createWidget function for our progressBar function aswell. Lets make it generic, we don’t want to create only labels:

def createWidget[T](factory:Composite => T)(setups:T => Unit*)(parent:Composite) = {performSetup(factory(parent), setups)}

I took the liberty to also inline the val label – statement. Sweet, lets use it for progressbars as well:

    def label = createWidget(new Label(_, SWT.NONE))_
    def progressBar = createWidget(new ProgressBar(_, SWT.NONE))_
    def createWidget(factory:Composite=>Label)(setups:(Label => Unit)*)(parent:Composite) = {
 val label = factory(parent)
 performSetup(label, setups)
 }
    def performSetup[T](target:T, setups:Seq[T => Unit]) = { setups.foreach(setup => setup(target)) }
 

Not too bad. Since we have other traits with widgets than just Labels we want to be able to reuse this pattern there as well. For that purpose we move the functions to a new object, Framework

object Framework {
	def createWidget[T](factory:Composite => T)(setups:T => Unit*)(parent:Composite) = {
		performSetup(factory(parent), setups)
	}
	def performSetup[T](target:T, setups:Seq[T => Unit]) = {
		setups.foreach(setup => setup(target))
	}
}

That leaves us with the final result for our Labels trait looking like this:

import Framework._  
trait Labels {     
   def label = createWidget(new Label(_, SWT.NONE))_     
   def progressBar = createWidget(new ProgressBar(_, SWT.NONE))_ 
}

Not too bad, definatly better than what I started with anyway :)

About these ads

Written by johlrogge

January 14, 2009 at 1:12 am

Posted in learning, scala, Uncategorized

Tagged with ,

6 Responses

Subscribe to comments with RSS.

  1. Thanks for the nice post. As someone who is also trying to break out of his OO shackles, it’s good to see as many examples like this as possible, no matter how simple they are.

    Dave Ray

    January 14, 2009 at 3:21 am

  2. Indeed, a very useful piece for people new to Scala.

    When I read a book on Scala it seems to be relatively simple. But when all this _/currying magic starts in earnest I am lost pretty quickly :(

    Nick

    January 14, 2009 at 9:26 pm

  3. oh, fine, go ahead and rub it in — here i am, stuck with java at my day job, cursing it daily for not having the useful ability to do higher-order functional-esque abstraction. cry whimper moan complain.

    Raoul Duke

    January 14, 2009 at 10:01 pm

  4. Dave: You’re welcome :) I see that you also decided to share your experiences with Scala. The more the merrier.

    Nick: Thanks, I’m happy that my post seems to be read as I intended it, accessible for beginners. I thought it would be a good idea to write the post now before I start to think that all of this is obvious. I agree that FP can be a bit different at times. It helped me when I started to think of functions as “transforms”. Int => Long takes an int and transforms it to a Long.

    But I still get lost when functions start to return functions that return functions and so on. In this area I think scalas shorthand (extra ‘(‘ and ‘)’) for returning a function makes it a bit less dramatic but still confusing :). About currying I think of it as “constructing” a new function from an existing one in a similar way that you would construct an instance of an object with some parameters passed in the constructor.

    To me the command-pattern works as a rough equivalent.

    I guess whatever makes sense to you :)

    Raol:
    LOL, if it makes you feel any better, I daylight as a java-programmer as well. I don’t curse so much as forget to write types and ;. On top of that I start writing the types in the wrong place when I come home and code scala :)

    johlrogge

    January 15, 2009 at 11:34 am

  5. Thanks that was a great read. Any plans on publishing the whole source code?

    Bahadir Yagan

    January 23, 2009 at 2:57 am

  6. Bahadir:
    Thanks for the feedback!

    Regarding plans for releasing the source I have plans to realease it as “beerware” http://people.freebsd.org/~phk/ (the bottom of the page), not because I fancy beer but because I think it would be a suitable license freedom-wise for the end-user. I just need to find the time, perhaps during the weekend.

    johlrogge

    January 23, 2009 at 9:55 am


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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: