Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional application of one of two functions to one argument

Tags:

scala

I have two functions that take one argument, a String. I was to apply either one or the other based on some condition. This is what I attempted:

def foo(s: String) = { ... }
def bar(s: String) = { ... }
(if (condition) foo else bar)("baz")

But I get an error like this:

<console>:10: error: missing arguments for method foo;
follow this method with `_' if you want to treat it as a partially applied function
              (if (true) foo else bar)("baz")
                         ^

I tried writing foo_ but of course I got error: not found: value foo_. What's the correct way to express this idiom in Scala?

like image 671
2rs2ts Avatar asked Mar 18 '23 18:03

2rs2ts


1 Answers

You need a space between the method name and the underscore. This works fine:

def foo(s: String) = s + "-FOO"
def bar(s: String) = s + "-BAR"
val condition = true
(if (condition) foo _ else bar _)("baz")
// res0: String = baz-FOO

The underscore after the method name tells Scala that you want to want to pass the method as a higher-level function. From what I understand, this is a way to disambiguate whether you want to pass a method as a function or pass the result of a method with no arguments. For example:

def f = 1
val x = Some(f)

What should the type of x be? Will it be Some[Int] or Some[()=>Int]? It should default to the former, but if you want the latter you can use the underscore notation:

val y = Some(f _)

You have to deal with all this underscore nonsense because Scala methods aren't functions. If you declare foo and bar as functions rather than methods then your original code works as-is:

val foo = (s: String) => s + "-FOO"
val bar = (s: String) => s + "-BAR"
val condition = false
(if (condition) foo else bar)("baz")
// res1: String = baz-BAR
like image 177
DaoWen Avatar answered Apr 29 '23 08:04

DaoWen