Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally invoke member function without a temporary var

Tags:

scala

I have an expression returning an object, and I want to invoke a method on the resulting object only if a certain boolean condition is true. I want to get the result (whether the object, or the result of invoking the method on the object) in a val.

One way is to use a temporary var, such as in the following example, in which List(3, 1, 2) is the (potentially complicated) expression returning an object, list is the temporary var, and .sorted is the method I want to conditionally invoke:

import scala.util.Random

val condition = Random.nextBoolean
val result = {      
  var list = List(3, 1, 2);
  if (condition) list = list.sorted
  list
}

What would be the canonical way to do this, perhaps without using a temporary var?

Note that

if (condition) List(3, 1, 2).sorted else List(3, 1, 2)

is not quite satisfactory because List(3, 1, 2) may in general be a complicated expression that I don't want to repeat.

Here is one method I found that unfortunately involves giving explicit types (and is longer and more complicated than introducing a temporary var as above):

val condition = Random.nextBoolean
val result =
  (
    if (condition)
      {l: List[Int] => l.sorted}
    else
      identity(_: List[Int])
  ).apply(List(3, 1, 2))

I suspect there must be a tidier way that I have failed to recognize.

Update: A slightly less ugly method that unfortunately still requires explicit type information:

val condition = Random.nextBoolean    
val result = {
    l: List[Int] => if (condition) l.sorted else l
  }.apply(List(3, 1, 2))
like image 217
Andrew Moylan Avatar asked Apr 04 '13 22:04

Andrew Moylan


2 Answers

You can use the forward pipe operator:

implicit class PipedObject[A](value: A) {
  def |>[B](f: A => B): B = f(value)
}

scala> List(3, 1, 2) |> (xs => if (true) xs.sorted else xs)
res1: List[Int] = List(1, 2, 3)
like image 172
kiritsuku Avatar answered Sep 24 '22 20:09

kiritsuku


Starting Scala 2.13, the standard library now provides the chaining operation pipe which can be used to convert/pipe a value with a function of interest, and thus avoids an intermediate variable:

import scala.util.chaining._

List(3, 1, 2).pipe(list => if (condition) list.sorted else list)
like image 44
Xavier Guihot Avatar answered Sep 24 '22 20:09

Xavier Guihot