Reputation: 573
Suppose have 3 numbers:
val x = 10
val y = 5
val z = 14
and we want to do some logic like:
if (x + y > z) {
println(x + y)
} else if (x + y < z) {
println(-1)
} else {
println(0)
}
If our "z + y" operation is expensive we must calculate it exactly once:
val sum = x + y
if (sum > z) {
println(sum)
} else if (sum < z) {
println(-1)
} else {
println(0)
}
but I want more functional way like:
if (x + y > z) => sum { //This is will not compile :)
println(sum)
} else if (sum < z) {
println(-1)
} else {
println(0)
}
Something without needing another statement to store the result. Something that I can compound with another function, like:
if(x + y > z) sum {
if(sum + 10 > 100) other_sum {
... etc
PS. Match does not help:
x + y match {
case result if result > z => println(result)
case result if result < z => println(-1)
case _ => println(0)
}
or
val sum = x + y
sum match {
case _ if sum > z => println(sum)
case _ if sum < z => println(-1)
case _ => println(0)
}
It still looks bad.
Upvotes: 2
Views: 204
Reputation: 141
Why did you try to compare two int values, if scala has the Ordering implicit type class for Int and you may call compare method instead of code above? Use compare from java comparator
(5 : Int).compare(9: Int) == -1
def compare(that: A): Int
/** Returns true if `this` is less than `that`
*/
object Ordered {
/** Lens from `Ordering[T]` to `Ordered[T]` */
implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]):
Ordered[T] = new Ordered[T] { def compare(that: T): Int = ord.compare(x, that)
If you want to use strange logic which u wrote above you may create custom Ordered implicit instance and class for u wrapped value like this
final case class V(value: Int)
object V {
def pure(v: Int): V[Int] = V(v)
implicit orderV: Ordered[V] = (o: Ordered) => ???
implicit class VOps(v: Int) extends AnyVal {
def @(that: Int)(implicit o : Ordered[V]): Int = o.compareTo(pure(v), pure(that))
}
}
and after that use like this (x + y)@z
Upvotes: 0
Reputation: 27421
Calculating the sum
in a temporary variable is no less functional than your other solutions. And if the calculation is complex then you can use the name of the temporary variable to describe the result and make the code more readable.
If you want to compose it with other code then you can easily wrap it in a function.
Here is another way to avoid the temporary variable, though it is not necessarily any better than the others.
((sum: Int) =>
if (sum > z) {
println(sum)
} else if (sum < z) {
println(-1)
} else {
println(0)
}) (x + y)
Upvotes: 6
Reputation: 8584
Tim's answer is correct, but I would add that what you really want is a single expression. You stated that here, though you used the word "function" instead:
Something that I can compound with another function
However, Scala is already expression-based, so this is actually a single expression:
{
val sum = x + y
if (sum > z) {
sum
} else if (sum < z) {
-1
} else {
0
}
}
It returns either sum
, -1
, or 0
. You can even pass this result to println
directly. In fact, this is equivalent to your original code:
println({
val sum = x + y
if (sum > z) {
sum
} else if (sum < z) {
-1
} else {
0
}
})
Upvotes: 5