user811602
user811602

Reputation: 1354

Scala: Declare val in if condition

I have very generic use case. I have a method conditionMethod which return Int

def conditionMethod(..):Int = {..}

Now I have if condition using same method

if (conditionMethod(..) > 0){
  conditionMethod(..) + 23 // Any action
}

Problem is it is calling method conditionMethod two times. To solve this, another approach is

val tmp = conditionMethod(..)
if (tmp > 0){
  tmp + 23 // Any action
}

What I don't like in this is I have to define a variable with larger scope.

Can I do something like

if ((val tmp = conditionMethod(..)) > 0){  // tmp variable in if condition itself 
  tmp + 23 // Any action
}

Scala version: 2.11

Upvotes: 8

Views: 5789

Answers (3)

Xavier Guihot
Xavier Guihot

Reputation: 61666

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

import scala.util.chaining._

13.pipe(res => if (res > 0) res else res + 23 ) // 13

This is actually a very close variant of a match statement and can as well be written as such:

-27 pipe { case res if (res > 0) => res case res => res + 23 } // -4

Upvotes: 7

jwvh
jwvh

Reputation: 51271

You could fold over a single element collection.

Seq(conditionMethod(..)).fold(0){case (z,x) =>
  if (x>z) x+23  // any action as long as the result is an Int
  else     x
}

If your "action" doesn't result in an Int then you could use foldLeft. Here's the same thing returning a String.

Seq(conditionMethod(..)).foldLeft(""){case (_,x) =>
  if (x>0) {
    x+23  // any action as long as if/else types match
    "string"
  }
  else "xxx"
}

Upvotes: 3

Thilo
Thilo

Reputation: 262534

You can keep the scope really tight:

val result = {
  val tmp = methodCall()
  if (tmp>0) tmp else tmp+23
}

Or use match

methodCall() match {
   case x if x <= 0 => x + 23
   case x => x
}

Upvotes: 10

Related Questions