7

I am trying to chain together some basic functions using Futures returned from a slick action and I'm hitting some pretty trivial stumbling blocks.

Both the andThen and onSuccess methods require a PartialFunction passed as a parameter. My understanding is probably quite flawed but after reading about anonymous functions it seems like andThen needs to know your anonymous function with cater for any Success or Failure input.

Given onSuccess already only caters for the Success case why does it still need to be a PartialFunction?

This block of code my indicate the problem I am having:

val db = Database.forConfig("h2mem1")

try {
  val f = db.run(setupCommands)
    .onSuccess { println(_) }

  Await.ready(f, 10.seconds )
}
finally db.close

I get a compile error:

[error]  found   : Unit => Unit
[error]  required: PartialFunction[Unit,?]
[error]         .onSuccess { println(_) }
GoldenFish
  • 217
  • 2
  • 9
  • 1
    @cmbaxter That's `onComplete`, not `onSuccess`. My guess: consistency with `onFailure`. – Michael Zajac Jul 06 '15 at 19:24
  • 2.11.6 - These [docs](http://www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.concurrent.Future) suggest PartialFunction? – GoldenFish Jul 06 '15 at 19:24
  • I think the better question is why does `onComplete` not also take a partial function? I think the other 3 were put in place with side effecting with conditions in mind and PFs are good for the conditions part (pattern matching). I'm just not sure why `onComplete` (also appears to be for side effecting given `Unit` as return type) didn't follow suit. – cmbaxter Jul 06 '15 at 19:45
  • I'm not too familiar with the term "side effecting" but the [docs](http://docs.scala-lang.org/overviews/core/futures.html) suggest that andThen and onSuccess are for this. The difference seems to be that they return another Future so that they can be chained together. – GoldenFish Jul 06 '15 at 19:52
  • Sorry, onComplete, onSuccess and onFailure all return Unit, andThen returns a Future. – GoldenFish Jul 06 '15 at 19:55

2 Answers2

3

They did it so you can pattern match on the result, though I agree that it seems needless, I don't really use onSuccess and prefer to map and flatMap my futures:

  val f = Future.successful("test")

  f.onSuccess({
    case "test" => println("Worked")
    case x: String => println(s"Kind of worked: $x")
  })

In the case of more advanced data types I could see this being more useful:

  val fOpt = Future.successful(Option("Test"))

  fOpt.onSuccess({
    case Some(x) => println(x)
    case None => println("None")
  })

Really this is probably just coming from the actor api since when you ask an actor you don't know the return type, you need to pattern match on it since it's Any:

  val actor:ActorRef = ???

  val fAny = actor ? "asking"

  fAny.onSuccess({
    case x:String => println(s"Something String $x")
    case x:Int => println(s"Something Int $x")
    case x => println(s"Something else $x")
  })
Noah
  • 13,821
  • 4
  • 36
  • 45
  • 1
    Though, you can use the pattern matching syntax for regular functions, too. – Owen Jan 12 '16 at 21:45
  • @Owen: Yeah, that's what puzzles me too. If I want to pattern match/pass a partial function, I can just do that at any time. Why do we ever need PartialFunction as an argument type? – kornfridge Mar 27 '17 at 08:38
1

Well, you can just pass it a PartialFunction, if it needs one:

db.run(setupCommands).onSuccess(PartialFunction(println))

Or:

db.run(setupCommands).onSuccess { case result => println(result) }
Kolmar
  • 14,086
  • 1
  • 22
  • 25