I come from Groovy and it has a .with
method on every type which accepts a single-argument closure; the argument is the object on which the .with
method is being called. This allows a very cool technique of extending the functional chaining capabilities, which releases you from obligation to introduce temporary variables, factors your code, makes it easier to read and does other niceties.
I want to be able to do something like this:
Seq(1, 2, 3, 4, 5)
.filter(_ % 2 == 0)
.with(it => if (!it.isEmpty) println(it))
Instead of
val yetAnotherMeaninglessNameForTemporaryVariable =
Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0)
if (!yetAnotherMeaninglessNameForTemporaryVariable.isEmpty)
println(yetAnotherMeaninglessNameForTemporaryVariable)
In other words in the first example the .with
is kinda similar to .foreach
but instead of iterating thru the items of the object it is being called once on the object itself. So it
is equal to Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0)
.
Since I was very surprised not to find anything like that in Scala, my questions are:
Update: An appropriate feature request has been posted on the Scala issue tracker: https://issues.scala-lang.org/browse/SI-5324. Please vote and promote
There doesn't exist any such method in the standard library, but it's not hard to define your own.
implicit def aW[A](a: A) = new AW(a)
class AW[A](a: A) {
def tap[U](f: A => U): A = {
f(a)
a
}
}
val seq = Seq(2, 3, 11).
map(_ * 3).tap(x => println("After mapping: " + x)).
filter(_ % 2 != 0).tap(x => println("After filtering: " + x))
EDIT: (in response to the comment)
Oh, I misunderstood. What you need is there in the Scalaz library. It comes under name |>
(referred to as pipe operator). With that, your example would look like shown below:
Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0) |> { it => if(!it.isEmpty) println(it) }
If you cannot use Scalaz, you can define the operator on your own:
implicit def aW[A](a: A) = new AW(a)
class AW[A](a: A) {
def |>[B](f: A => B): B = f(a)
}
And it's not a bad practice to pimp useful method(s) on existing types. You should use implicit conversions sparingly, but I think these two combinators are common enough for their pimps to be justifiable.
There is some syntax for this pattern included in Scala:
Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0) match { case it => if (!it.isEmpty) println(it) }
However, this is no accepted idiom so you should maybe refrain from (ab)using it.
If you dislike inventing loads and loads of names for dummy variables, remember that you can use scope braces:
val importantResult = {
val it = Seq(1,2,3).filter(_ % 2 == 0)
if (!it.isEmpty) println(it)
it
}
val otherImportantResultWithASpeakingVariableName = {
val it = // ...
/* ... */
it
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With