0

Often I have functions like this:

{
  val x = foo;
  bar(x);
  x
}

For example, bar is often something like Log.debug.

Is there a shorter, idiomatic way how to run it? For example, a built-in function like

def act[A](value: A, f: A => Any): A = { f(value); value }

so that I could write just act(foo, bar _).

Petr
  • 62,528
  • 13
  • 153
  • 317

3 Answers3

1

I'm not sure if i understood the question correctly, but if i do, then i often use this method taken from the Spray toolkit:

def make[A, B](obj: A)(f: A => B): A = { f(obj); obj }

then you can write the following things:

utils.make(new JobDataMap()) { map =>
  map.put("phone", m.phone)
  map.put("medicine", m.medicine.name)
  map.put("code", utils.genCode)
}
4lex1v
  • 21,367
  • 6
  • 52
  • 86
1

Using your act function as written seems perfectly idiomatic to me. I don't know of a built-in way to do it, but I'd just throw this kind of thing in a "commons" or "utils" project that I use everywhere.

If the bar function is usually the same (e.g. Log.debug) then you could also make a specific wrapper function for that. For instance:

def withDebug[A](prefix: String)(value: A)(implicit logger: Logger): A = {
  logger.debug(prefix + value)
  value
}

which you can then use as follows:

implicit val loggerI = logger

def actExample() {
  // original method
  val c = act(2 + 2, logger.debug)

  // a little cleaner?
  val d = withDebug("The sum is: ") {
      2 + 2
    }
  }

Or for even more syntactic sugar:

object Tap {
  implicit def toTap[A](value: A): Tap[A] = new Tap(value)
}

class Tap[A](value: A) {

  def tap(f: A => Any): A = {
    f(value)
    value
  }

  def report(prefix: String)(implicit logger: Logger): A = {
    logger.debug(prefix + value)
    value
  }
}

object TapExample extends Logging {
  import Tap._
  implicit val loggerI = logger

  val c = 2 + 2 tap { x => logger.debug("The sum is: " + x) }

  val d = 2 + 2 report "The sum is: "

  assert(d == 4)
}

Where tap takes an arbitrary function, and report just wraps a logger. Of course you could add whatever other commonly used taps you like to the Tap class.

David Soergel
  • 1,709
  • 1
  • 11
  • 15
  • Ah, I agree that "tap" is a nice name for it. Also it looks like all of these solutions are well described in [Equivalent to Ruby's #tap method in Scala](http://stackoverflow.com/questions/16742060/equivalent-to-rubys-tap-method-in-scala) and [how to keep return value when logging in scala](http://stackoverflow.com/questions/9671620/how-to-keep-return-value-when-logging-in-scala) – David Soergel Jul 10 '13 at 15:26
0

Note that Scala already includes a syntactically heavyweight version:

foo match { case x => bar(x); x }

but creating the shorter version (tap in Ruby--I'd suggest using the same name) can have advantages.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407