Stackable traits

Today I was playing around with some code to show people how Scala traits (more specifically stackable traits) make it much easier to decompose your ‘problem’ into generic and reusable building blocks.

One of the issues we recently looked at was retrying a query which failed for some reason; which might not sound like something you’ed want to retry.. but believe me; in some cases it makes sense.

So, say we have a very simple repository definition to access a database:

We can now ‘implement’ a couple of dummy repositories to play with:

As you can see we have three different repositories, with their own unique characteristics. Calling the first two repositories would result in exceptions. The second one does however work when we call retry the call a couple of time. Now, enter the Retrying trait:

As you probably guess from the name: this trait will add retrying functionality to the class which it is mixed in to. So, how does it work:

  • The abstract modifier on the override of the withConnection allows us to change the behavior of the method we’re overriding
  • The super.withConnection call in the retry function is still referring to the actual implementation of the class the trait is mixed in to (well, or the first override in the inheritance chain)

We can mix this trait into a repository in the class definition, or… more interesting… at instantiation time:

The above code will print something like:

number of tries left: 3
number of tries left: 2
number of tries left: 1
number of tries left: 0
failed result: None
number of tries left: 3
number of tries left: 2
number of tries left: 1
success result: Some(should fail first, succeed later)
number of tries left: 3
success result: Some(should not fail result)

Surely this is only the tip of the iceberg. But as you can see, this is a very powerful mechanism to create a very modular set of very specialized components; each with their very specific purpose. High cohesion… low coupling!

Ow… and yes I notice my retry function is not tail recursive; still working on that…

This entry was posted in scala. Bookmark the permalink.

5 Responses to Stackable traits

  1. What do you mean it is not tail recursive? I think it is. Try by putting @Tailrec on it.

  2. peter says:

    Well, that was my first impression as well… but adding @tailrec showed me it is not. The (implicit) return at the end of the function is the last operation…

  3. I see. Another example where exceptions and FP don’t go well together.

  4. I see. Yet another example where exceptions and FP don’t go well together.

  5. This one is tail recursive:


    @tailrec
    private def retry(f: (Connection => Option[T]), times: Int = 3): Option[T] = {
    val r = try {
    println("number of tries left: %d".format(times))
    Some(super.withConnection(f))
    } catch {
    case _ if times == 0 => Some(None)
    case _ => None
    }
    r match {
    case Some(x) => x
    case None => retry(f, times - 1)
    }
    }

    Note I wrapped the end result in another Option :)
    Note also that using getOrElse on r will not work.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>