Sebastien Lorber
Sebastien Lorber

Reputation: 92200

Future.onComplete: can't understand the method signature

  /** When this future is completed, either through an exception, or a value,
   *  apply the provided function.
   *
   *  If the future has already been completed,
   *  this will either be applied immediately or be scheduled asynchronously.
   *
   *  $multipleCallbacks
   *  $callbackInContext
   */
  def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit

Basic usage seems to be:

  result.onComplete({
    case Success(listInt) => {
      //Do something with my list
    }
    case Failure(exception) => {
      //Do something with my error
    }
  })

This function seems useful to produce side effects as it returns Unit (like logging completion) What I don't understand is what is this type U that the function returns. Is the return type of the function we provide really useful? How is it used by Scala?

The same question could apply to onSuccess and onFailure

Edit: to make it clearer, what's the benefits of def onComplete[U](func: Try[T] => U) over def onComplete(func: Try[T] => Unit)?


Edit:

Chirlo is right, the function with type U is more flexible and we can pass it more easily existing functions that do not return Unit.

type T = String

def onComplete[U](func: Try[T] => U): Unit = { }
def onComplete2(func: Try[T] => Unit): Unit = { }

// Existing function that does not return Unit
def log[T]( t : Try[T]): Int = 0

onComplete(log) // This compiles fine
onComplete2(log) // This does not compile

Upvotes: 6

Views: 2279

Answers (2)

Chirlo
Chirlo

Reputation: 6130

It makes the function more flexible. If it would return Unit, you could just pass it functions Try[T] => Unit, but by returning U, you can pass it any function that takes Try[T] as a parameter, that you may already have lying around. For example:

def log[T]( t : Try[T]): Int =  //write to file and return 0  if Ok, else 128

This functions has side effects but also returns a value. You can now pass this function to your Future although it doesn't return Unit, the result is thrown away but you can reuse an already existing function.

Upvotes: 1

GKV
GKV

Reputation: 892

a very simple example should clear the cloud

val a = Future(1/2)
a.onComplete[String]({
  case Success(1) => "StringValue"         
})

here U is String and T is Int in the Success.

Now in most of the cases scala understands what is the data type and we need not to specifically mention the type U and T

the above example will result into an error if we change String "StringValue" to something else

val a = Future(1/2)
a.onComplete[String]({
  case Success(1) => 1
})

compilation error- type mismatch; found : Int(1) required: String

if however we remove String from complete and not forcing return type as String, it will take any type

val a=Future(1/2)
a.onComplete({
  case Success(1)=>1
  case Success(2) => "we found two"  
  case Success(3) => 1.0f
  case Success(_) => new RuntimeException("it was not expected")
})

compiles fine. and hence gives us power of returning multiple types depending upon your usecase

Upvotes: 0

Related Questions