A promessa e o futuro são conceitos complementares. O Futuro é um valor que será recuperado, bem, em algum momento no futuro e você pode fazer coisas com ele quando esse evento acontecer. É, portanto, o ponto final de leitura ou saída de um cálculo - é algo de onde você recupera um valor.
Uma promessa é, por analogia, o lado da escrita do cálculo. Você cria uma promessa que é o lugar onde você colocará o resultado do cálculo e dessa promessa você obterá um futuro que será usado para ler o resultado que foi colocado na promessa. Ao cumprir uma promessa, seja por fracasso ou sucesso, você acionará todo o comportamento que estava vinculado ao futuro associado.
Com relação à sua primeira pergunta, como pode ser isso para uma promessa p que temos p.future == p
. Você pode imaginar isso como um buffer de item único - um contêiner que está inicialmente vazio e você pode armazenar um valor que se tornará seu conteúdo para sempre. Agora, dependendo do seu ponto de vista, isso é uma promessa e um futuro. É uma promessa para quem pretende escrever o valor no buffer. É um futuro para quem espera que esse valor seja colocado no buffer.
Especificamente, para a API simultânea Scala, se você der uma olhada no traço Promise aqui, poderá ver como os métodos do objeto complementar Promise são implementados:
object Promise {
/** Creates a promise object which can be completed with a value.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
/** Creates an already completed Promise with the specified exception.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
/** Creates an already completed Promise with the specified result.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
Agora, essas implementações de promessas, DefaultPromise e KeptPromise podem ser encontradas aqui . Ambos estendem um pequeno traço básico que por acaso tem o mesmo nome, mas está localizado em um pacote diferente:
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
Então você pode ver o que eles querem dizer p.future == p
.
DefaultPromise
é o buffer que estava me referindo acima, enquanto KeptPromise
é um buffer com o valor colocado desde sua criação.
Em relação ao seu exemplo, o bloco futuro que você usa ali cria uma promessa nos bastidores. Vamos olhar a definição de future
em aqui :
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
Seguindo a cadeia de métodos, você acaba no impl.Future :
private[concurrent] object Future {
class PromiseCompletingRunnable[T](body: => T) extends Runnable {
val promise = new Promise.DefaultPromise[T]()
override def run() = {
promise complete {
try Success(body) catch { case NonFatal(e) => Failure(e) }
}
}
}
def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
val runnable = new PromiseCompletingRunnable(body)
executor.execute(runnable)
runnable.promise.future
}
}
Então, como você pode ver, o resultado que você obtém do seu bloco produtor é transformado em uma promessa.
EDIÇÃO DEPOIS :
Com relação ao uso no mundo real: na maioria das vezes, você não lida diretamente com as promessas. Se você usar uma biblioteca que realiza computação assíncrona, trabalhará apenas com o futuro retornado pelos métodos da biblioteca. As promessas são, neste caso, criadas pela biblioteca - você está apenas trabalhando com a leitura do que esses métodos fazem.
Mas se você precisar implementar sua própria API assíncrona, terá que começar a trabalhar com eles. Suponha que você precise implementar um cliente HTTP assíncrono em cima de, digamos, Netty. Então, seu código será parecido com este
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}