Namek Dev
a developer's log
NamekDev

Power of lambda in Xtend

April 2, 2016

The Console supports multiple tabs. By hitting CTRL+T  combination new tab is opened and auto-named. I decided to name tabs as “Tab 1”, “Tab 2”, etc. However, those tabs can be renamed and moved inbetween so auto-naming need an algorithm. I’ve done similiar operation few times but never done this specific things by using Lambda Expressions in Xtend. I was quite surprised by one small detail.

Required output and algorithm

It’s a very simple need but it makes me remember how specific and and far-sighted you need to be when designing requirements.

Algorithm goes like this:

  1. find all tabs named as Tab X , where X is a number (multiple digits)
  2. get the biggest number
  3. add 1 to the biggest number and use it for new tab name

“The biggest number” is a more wish than well-thought requirement. Between all tab names there could be no single tab named as Tab X . So “the biggest number” requirement could fail when operating on empty collection, e.g. by taking maximum number of collection would throw exception.

Modified algorithm:

  1. find all tabs named as Tab X , where X is a number (multiple digits)
  2. sort collected numbers by ascending order
  3. if there are no numbers then return1 as output, otherwise take max

However, point 3 now is specified as having wrong requirement priority  Let’s rewrite it:

  1. return max, or if there is no number then return 1 as output

The algorithm in Xtend

Let’s start with regular expression that simplifies filtering tabs and taking a number from input:

val numberedTabRegex = Pattern.compile("tab\\s*(\\d+)")

And here’s the algorithm:

val tabNumbers = tabPane.tabs
	.map[(it as ConsoleTab).headerText]
	.map[numberedTabRegex.matcher(it.toLowerCase)]
	.filter[it.find() && it.groupCount == 1]
	.map[it.group(1)].map[Integer.parseInt(it)]
	.sort

val newTabNumber = if (tabNumbers.empty) 1 else tabNumbers.last + 1
tab.headerText = "Tab " + newTabNumber

While same code would need couple of statements and brackets in Java, here’s almost one single expression. Almost one. I’m a bit judgemental in situations like this but in C# LINQ there’s are functions like FirstOrDefault  or  LastOrDefault . Xtend doesn’t have it so I needed to write condition for collection emptiness.

In the other hand, it’s quite nice, by comparing to Java 6. Notice keyword it which reduces repeating variable names in situations like here:

val tabNames = tabPane.tabs.map[tab | (tab as ConsoleTab).headerText]

we can have it like this:

val tabNames = tabPane.tabs.map[(it as ConsoleTab).headerText]
Daj Się Poznać, the-console, xtend
comments powered by Disqus