Conditional invocation of a method in Scala
Asked Answered
L

3

13

I've found this pattern quite a few times in my code:

  if (doIt)
    object.callAMethod
  else
    object

I'm wondering if there could be a syntactically more pleasing way to write the code above, especially to avoid the repetition of the object variable. Something like:

   // using the Scalaz "pipe" operator
   // and "pimping" f: T => T with a `when` method
   object |> (_.callAMethod).when(doIt)

Unfortunately the line above fails because the type inference requires a parameter type for (_.callAMethod).

My best approach for now is this:

    implicit def doItOptionally[T](t: =>T) = new DoItOptionally(t)
    class DoItOptionally[T](t: =>T) {
      def ?>(f: T => T)(implicit doIt: Boolean = true) = 
        if (doIt) f(t) else t
    } 

    implicit val doIt = true
    object ?> (_.callAMethod)

Not great because I have to declare an implicit val but this pays off if there are several chained calls:

     object ?> (_.callAMethod) ?> (_.callAnotherMethod)

Does anyone have a better idea? Am I missing some Scalaz magic here?

Lyingin answered 5/9, 2011 at 23:36 Comment(0)
S
18
class When[A](a: A) {
  def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a
}
implicit def whenever[A](a: A) = new When(a)

Example:

scala> "fish".when(_.length<5)(_.toUpperCase)
res2: java.lang.String = FISH
Sylvanite answered 5/9, 2011 at 23:47 Comment(2)
I didn't think of inverting the condition and the function, thanks!Lyingin
I also notice that a noun goes better here than an operator because the . needs to be used after "fish".Lyingin
T
4

I can't comment on your answer @Rex Kerr but a more concise way to do that would be:

implicit class When[A](a: A) {
  def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a
}

Just putting the implicit before the class allows you to omit the implicit function entirely.

Treasury answered 2/3, 2016 at 21:7 Comment(0)
I
0

If you represent your callAMethod as an endomorphism then you can use the monoid functionality. Something like:

object |> valueOrZero(doIt, Endo(_.callAMethod))

(might need a type parameter on the Endo)

Ist answered 2/3, 2016 at 23:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.