Manu Chadha
Manu Chadha

Reputation: 16723

How to understand function's signature of scala APIs?

I struggle at times to understand how to call a function. I am studying lists and am writing sample examples of its methods.

The andThen is defined as follows

def andThen[C](k: (A) ⇒ C): PartialFunction[Int, C]

I understand that I have to pass a function literal to andThen. So I created following code which works.

scala> val l = List (1,2,3,4)
l: List[Int] = List(1, 2, 3, 4)

//x:Int works
scala> val listAndThenExample = l.andThen((x:Int) => (x*2))
listAndThenExample: PartialFunction[Int,Int] = <function1>

//underscore works
scala> val listAndThenExample = l.andThen(_*2)
listAndThenExample: PartialFunction[Int,Int] = <function1>

As the list is of Integers, A has to be Int. C can be anything depending on the output of function literal.

The above makes sense.

Later I tried applyOrElse. Its signature is as follows

def applyOrElse[A1 <: Int, B1 >: A](x: A1, default: (A1) ⇒ B1): B1

From above, I understand that A1 can be Int or its subclass (upperbound) and some B1 will be the return type (depending on what I do in default function).

If my understanding of A1 and B1 is correct then x will be either Int or its subclass and the default function literal should take Int (or subclass) and return some B1. I tried to call the function as follows but it doesn't work when I use y:Int but works when I use _:Int. I do not understand why.

scala> val l = List (1,2,3,4)
l: List[Int] = List(1, 2, 3, 4)

//this doesn't work
cala> val listApplyOrElse = l.applyOrElse(y:Int,(x:Int)=>println("Wrong arg "+x))
<console>:12: error: not found: value y
       val listApplyOrElse = l.applyOrElse(y:Int,(x:Int)=>println("Wrong arg "+x))
                                           ^
//but underscor works
scala> val listApplyOrElse = l.applyOrElse(_:Int,(x:Int)=>println("Wrong arg "+x))
listApplyOrElse: Int => AnyVal = <function1>

Question - Why did both x:Int and _:Int worked for andThen but not for applyOrElse?

Question - what is 'A' and why is B1 related to A?

Upvotes: 1

Views: 133

Answers (2)

Max
Max

Reputation: 22325

According to the documentation, applyOrElse(x, default) is equivalent to

if (pf isDefinedAt x) pf(x) else default(x)

In this case your partial function is a list i.e. a function from indices (0 to 3) to values (1,2,3,4). So when you do

l.applyOrElse(y,(x:Int)=>println("Wrong arg "+x))

you're saying "Call l(y) if it makes sense, otherwise println("Wrong arg"+y)". The compiler reasonably responds, "What is y?"

If you use an actual value it works as expected

l.applyOrElse(3 ,(x:Int)=>println("Wrong arg "+x)) // returns 4
l.applyOrElse(8 ,(x:Int)=>println("Wrong arg "+x)) // prints Wrong arg 8

Using an underscore does something completely different, you get a partially applied function (which is completely different from a partial function!)

val f = l.applyOrElse(_:Int, (x:Int)=>println("Wrong arg "+x))
f(8) // prints Wrong arg 8

Upvotes: 1

puhlen
puhlen

Reputation: 8529

You haven't declared y, so trying to use it is an error. _:Int works because this is now creating a partially applied function. Notice the return type is not a value, but a function. This returned function is the applyOrElse with the second argument already provided (but not the first).

With your andThen example, the use of _ means something different, specifically it is a shorthand notation for a function literal.

Upvotes: 0

Related Questions