1

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.

WeiChing 林煒清
  • 4,452
  • 3
  • 30
  • 65
  • Apply has an mandatory argument that you missed, to use apply explicitly the index should be passed: Seq.apply(0).orElse(Seq(1)) – Alex Evseenko Apr 13 '18 at 14:33
  • @AlexEvseenko That's the same as `Seq(0).orElse(Seq(1))`. If you meant `Seq(0).apply(0).orElse(Seq(1))`, then it's invalid, because `Int` has no method `orElse`. – Andrey Tyukin Apr 13 '18 at 14:47
  • I meant statement from the original post: **@ Seq(0).apply.orElse(Seq(1)) cmd3.sc:1: missing argument list for method apply in trait SeqLike** – Alex Evseenko Apr 13 '18 at 14:50
  • On EDIT: For this to be type-safe, the `PartialFunction` would have to be F-polymorphically bounded by the return type of the `orElse`-method. Given how deeply `PartialFunction` is embedded in the standard API and the compiler, this will probably never happen. If you don't need this type-safely, it would *theoretically* be possible to implement the `orElse` in this way, but it would be more of a hack... May I ask *why* you need this? Wouldn't your own "pimp-my-library"-pattern do the trick? – Andrey Tyukin Apr 14 '18 at 01:28

1 Answers1

5

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.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • 1
    I think the wording of the second sentence is misleading. When `pfA.orElse(pfB)` is applied to `x`, `pfB` will only be invoked if `pfA` is undefined at `x`. So, it is confusing to say that "you override the returned value" because there is no returned value—if there were, it would not be overridden. – Joe Pallas Apr 13 '18 at 18:42
  • @JoePallas You are right. This statement was just plain wrong. I updated the answer. Thank you! – Andrey Tyukin Apr 13 '18 at 18:48
  • in console `Seq(0); res46: Seq[Int] = List(0)` Seq(0) is List now ? – WeiChing 林煒清 Apr 14 '18 at 00:43
  • so that the type of Seq is dynamic between List and PartialFunction ? – WeiChing 林煒清 Apr 14 '18 at 00:44
  • @WeiChingLin It simply *extends* `PartialFunction`. Look up in the inheritance hierarchy for `Seq`: it's `Seq[A] extends PartialFunction[Int, A]`. – Andrey Tyukin Apr 14 '18 at 00:52
  • 1
    thankyou, I thought it would behave as Option. I should have first saw what it does from looking at type hierarchy. – WeiChing 林煒清 Apr 14 '18 at 01:42