import static extension de.fhg.fokus.xtensions.function.FunctionExtensions.*
import java.time.LocalDate
// ...
val ()=>LocalDate inOneYear = [LocalDate.now.plusYears(1)]
val (LocalDate)=>String yearString = [it.year.toString]
val ()=>String nextYear = inOneYear.andThen(yearString)
println(nextYear.apply)
Extensions to Functions
Xtend provides own functional interfaces in the
org.eclipse.xtext.xbase.lib.Functions
Interface. These are used all over the Xtend standard library and they allow a compact declaration syntax, e.g. the type
Function1<? super String,? extends String>
can be written as (String)⇒String
.
Extensions to Xtends functional interfaces are provided in de.fhg.fokus.xtensions.function.FunctionExtensions
.
This library’s FunctionExtensions
provides another overload of the method andThen
which allows composition of a
()⇒T
function with a (T)⇒U
function, resulting in a composed ()⇒U
function.
Example:
Inspired by the |>
operator of F# and Elixir, this library introduces the >>>
operator,
which can be seen as a "pipe through" operator. It takes the value of the left hand side and
calls the function on the right hand side with the value. This means that
val (X)=>Y f = ...
val X x = ...
x >>> f
// equal to
f.apply(x)
This is especially handy when having to call several functions in a row,
so a.apply(b.apply(x))
can be written as x >>> b >>> a
.
It can also be useful to transforming transform the value returned by a method call
before assigning it to a final variable without having to define a separate method.
It can also be used like the ⇒
operator (to have a value as a context value it
)
just with a different return value.
Example:
import static extension de.fhg.fokus.xtensions.function.FunctionExtensions.*
import java.nio.file.Paths
// ...
val path = System.getProperty("user.home") >>> [Paths.get(it)]
println(path.parent)
The >>>
operator is overloaded to also destructure a Pair
value into key
and value
on call.
This means that the left hand side of the operator must be evaluated to a value of type Pair and the
right hand side of the operator must be a function with two parameters of the types of key and value of
the Pair (K,V)⇒Y
.
Example:
import static extension de.fhg.fokus.xtensions.function.FunctionExtensions.*
// ...
val list = #["foo", "bar", "foo", "baz", "foo", "bar"]
list.splitHead
>>> [head,tail| head -> tail.toSet.size]
>>> [head,remaining| '''Head: "«head»", remaining: «remaining» unique elements''']
>>> [println(it)]
// ...
def <T> Pair<T,Iterable<T>> splitHead(Iterable<T> elements) {
elements.head -> elements.tail
}
To compose functions, the shortcut operators >>
for andThen
and <<
for compose
were introduced.
Example:
import static extension de.fhg.fokus.xtensions.function.FunctionExtensions.*
import java.time.LocalDate
// ...
val (LocalDate)=>LocalDate oneYearLater = [it.plusYears(1)]
val (LocalDate)=>String yearString = [it.year.toString]
val (LocalDate)=>String yearAfter = oneYearLater >> yearString
LocalDate.now >>> yearAfter >>> [println(it)]
When working with the Xtend extension methods on Iterator
and Iterable
sometimes
(X)⇒Boolean
types are needed, e.g. for the exists
and filter
combinator.
Unfortunately the Xtend boolean functions do not have the composition functions as the
Java 8 java.util.function.Predicate
interface. This library’s FunctionExtensions
class does provides the equivalent methods and
, or
, and negate
.
import static extension de.fhg.fokus.xtensions.function.FunctionExtensions.*
// ...
val (String)=>boolean notThere = [it.nullOrEmpty]
val (String)=>boolean tooShort = [it.length < 3]
val (String)=>boolean valid = notThere.or(tooShort).negate
#["ay", "caramba", null, "we", "fools"]
.filter(valid)
.forEach[
println(it)
]
Tip
|
Related JavaDocs: |