WeiChing 林煒清
WeiChing 林煒清

Reputation: 4469

Scala unexpected output for List.orElse

I expect the following code output with Seq(0), instead it returns a function ?

@ Seq(0).orElse(Seq(1))
res2: PartialFunction[Int, Int] = <function1>

I suspected at first that via syntax sugar it orElse on apply function, but it didn't since by trying:

@ Seq(0).apply.orElse(Seq(1))
cmd3.sc:1: missing argument list for method apply in trait SeqLike
....(omit)

I checked in IntellJ that there's no implicit conversion.
What happens?


EDIT: what I wish is:
Seq.empty.orElse(Seq(1)) == Seq(1)
Seq(0).orElse(Seq(1)) == Seq(0)


thanks @AndreyTyukin answer.
In one line, orElse has different semantic in different type , now Seq inherits PartialFunction not Option, so does the orElse behavior.

Upvotes: 1

Views: 1293

Answers (1)

Andrey Tyukin
Andrey Tyukin

Reputation: 44908

The Seq(0) is treated as a PartialFunction that is defined only at index 0, and produces as result the constant value 0 if it is given the only valid input 0.

When you invoke orElse with Seq(1), a new partial function is constructed, that first tries to apply Seq(0), and if it finds nothing in the domain of definition of Seq(0), it falls back to Seq(1). Since the domain of Seq(1) is the same as the domain of Seq(0) (namely just the {0}), the orElse does essentially nothing in this case, and returns a partial function equivalent to Seq(0).

So, the result is again a partial function defined at 0 that gives 0 if it is passed the only valid input 0.


Here is a non-degenerate example with sequences of different length, which hopefully makes it easier to understand what the orElse method is for:

val f = Seq(1,2,3).orElse(Seq(10, 20, 30, 40, 50))

is a partial function:

f: PartialFunction[Int,Int] = <function1>

Here is how it maps values 0 to 4:

0 to 4 map f

// Output: Vector(1, 2, 3, 40, 50)

That is, it uses first three values from the first sequence, and falls back to the second sequence passed to orElse for inputs 3 and 4.


This also works with arbitrary partial functions, not only sequences:

scala> val g = Seq(42,43,44).orElse[Int, Int]{ case n => n * n }
g: PartialFunction[Int,Int] = <function1>

scala> 0 to 10 map g
res7 = Vector(42, 43, 44, 9, 16, 25, 36, 49, 64, 81, 100)

If you wanted to select between two sequences without treating them as partial functions, you might consider using

Option(Seq(0)).getOrElse(Seq(1))

This will return Seq(0), if this is what you wanted.

Upvotes: 5

Related Questions