Background: I’ve recently had the opportunity to code with Scala for the acceptance tests in some of the AWS projects we’re doing at work. I read more cool stuff about Scala every day and I’m trying to adopt useful features as I see them. Today I experimented with Scala’s inbuilt regular expression matching, string interpolation, apply method and companion objects.

Problem: Multiple developers have worked on our library component for interacting with Amazons SQS service and have used several different ways for referencing queues - sometimes by the queue’s ARN and sometimes by its URL. I wanted to be able to retrieve both the URL and ARN from an object constructed from just one of those values.

object SQSQueue {
  val arnRegex="""^arn:aws:sqs:([\w\-]+):(\d+):([\w\-]+)$""".r
  val urlRegex="""^https://sqs\.([\w\-]+)\.amazonaws\.com/(\d+)/([\w\-]+)$""".r

  def apply(queueIdentifier: String): Option[SQSQueue] = {
    queueIdentifier match {
      case urlRegex(region, account, name)
          => Some(new SQSQueue(region, account, name))
      case arnRegex(region, account, name)
          => Some(new SQSQueue(region, account, name))
      case _ => None
    }
  }
}

class SQSQueue(val region: String, val account: String, val name: String) {
  lazy val arn = s"arn:aws:sqs:$region:$account:$name"
  lazy val url = s"https://sqs.$region.amazonaws.com/$account/$name"
}

Usage:

val queueUrl = "https://sqs.eu-west-1.amazonaws.com/123456789012/queuename"
val queueArn = "arn:aws:sqs:eu-west-1:123456789012:queuename"
val someQueueByUrl: Option[SQSQueue] = SQSQueue(queueUrl)
val someQueueByArn: Option[SQSQueue] = SQSQueue(queueArn)

assert(someQueueByUrl.get.url == someQueueByArn.get.url)
assert(someQueueByUrl.get.arn == someQueueByArn.get.arn)

Explanation: So what’s going on here?

  1. The object is known as a Companion Object. It provides similar functionality to Java’s static methods.
  2. The triple quotes allow for unescaped control characters so you don’t need to escape the backslashes used in the regex.
  3. The regular expressions match SQS ARN and URL formats respectively with capturing groups for the region, account number and queue name.
  4. The ‘.r’ at the end of the regex strings compiles them.
  5. The apply function is syntactic sugar. When an object does only one thing, if its one function is named ‘apply’ the behaviour can be invoked without the function name i.e. SQSQueue.apply() == SQSQueue().
  6. The queue identifier passed into apply is matched against the URL and ARN regular expressions. The sexy thing here is that the captured strings are automatically pulled out and made available in the following block. This allows me to return a new SQSQueue instance created with the parameters pulled directly from the matched string.
  7. Rather than return an instance of SQSQueue, an Option[SQSQueue] is returned. This is a Scala container object that wraps either an actual SQSQueue object or a special ‘None’ reference. That means we can handle the error predictably if the supplied string matched neither an SQS ARN or URL.
  8. The three vals of the SQSQueue constructor become public members of the class so the constituent parts of the queue name can be accessed.
  9. But wait, there’s more: the SQSQueue instance has two other public vals that are composed using Scala’s string interpolation, simply by prefixing the string with ‘s’ and dropping variables in there that begin with ‘$’.
  10. And that’s not all. Those aren’t normal vals. They’re lazy vals! That means they’re only evaluated the first time they’re used.

Conclusion: What started as a wrapper class for some SQS queue information turned into an experiment into the interesting things that can be done with the tools that Scala provides. While some of these may seem overkill for this situation, it was a useful exercise that led me to some interesting language features which will save time without sacrificing the readability of the code. The inline regex matching and capturing group extraction feels particularly powerful. I look forward to developing with Scala in 2014.