Общий тип в Promise - PullRequest
       43

Общий тип в Promise

1 голос
/ 03 октября 2019

Я разработал класс Task для синхронного вычисления некоторого значения T. Теперь я хочу предоставить способ асинхронного получения значения.

Впервые я использую Promise в Scala. Я написал следующий код:

abstract class Task[+T](
...

    final def result: Try[T] = {
        if (state != TaskState.Terminated)
            throw new IllegalStateException("Task must be terminated")
        cached_result
    }
}



// OTHER CLASS
    private val executedTasks = HashMap[TaskID, Task[_]]() 
    private val promises = HashMap[TaskID, Promise[Any]]()

    ...

    def onTaskEvent(taskEvent: TaskEvent): Unit = {
        ...
        val task: Task[_] = ...
        promises.get( task.id ).foreach( p => p complete task.result ) // fulfill the promise with a Try[_]
        ...
    }

    ...

    /**
    * if the task exists and is terminated I return the result immediately
    * otherwise I make a promise
    */
    def getTaskResult(uuid: TaskID): Future[_] = {
        executedTasks.get(uuid) match {
            case Some(task) if task.state == TaskState.Terminated => Future.fromTry(task.result)
            case _ => {
                val p = Promise[Any]()
                promises.put(uuid, p)
                p.future
            }
        }
    }

Этот код работает, но я хочу избавиться от этого уродливого Any в Promise и продолжать использовать универсальные типы. Когда я пытался использовать Promise[_], я получал загадочную ошибку компилятора типа "expected: Try[_] actual: Try[_$1]" или "Promise[_]: unbound wildcard type".

Спасибо за вашу помощь.

Ответы [ 3 ]

0 голосов
/ 04 октября 2019

В конце концов я нашел подходящий дизайн для своих нужд, в то же время заставляя печатать. По сути, идея заключается в том, что вызывающий getTaskResult знает, какой тип он ожидает для данной задачи. Поэтому нет ничего необычного в том, чтобы приводить элементы универсальной коллекции к ожидаемому типу при их извлечении. Я решил также проблему множественных обещаний для одной и той же задачи с мультикартой.

    protected val promises = new HashMap[TaskID, collection.mutable.Set[Promise[_]]] with collection.mutable.MultiMap[TaskID, Promise[_]]

    ...

    protected def makePromise[T](task: Task[T]): Promise[T] = {
        val p = Promise[T]()
        promises.addBinding(task.id, p)
        p
    }

    protected def fulfillPromise[T](task: Task[T]): Unit =
        promises.remove(task.id).foreach(p => p.map(_.asInstanceOf[Promise[T]]).foreach(_ complete task.result))


    protected def futureResult[T](task: Task[T]): Future[T] = {
        if (task.state == TaskState.Terminated)
            Future.fromTry(task.result)
        else
            makePromise(task).future
    }


    def getTaskResult[T](uuid: TaskID): Future[T] =
        taskTracker.getTaskById(uuid).map(_.asInstanceOf[Task[T]]).fold(throw new Exception("Unknown task"))(futureResult(_))
0 голосов
/ 05 октября 2019

гул, я чувствую, что с этой функцией все еще есть проблема:

protected def fulfillPromise[T](task: Task[T]): Unit =
        promises.remove(task.id).foreach(p => p.map(_.asInstanceOf[Promise[T]]).foreach(_ complete task.result))

Она не защищена от ClassCastException в области уведомлений, я думаю, что здесь есть необходимость использовать TypeTag в Promise.

0 голосов
/ 03 октября 2019

Проблема в том, что нет никакой связи между параметрами типа Task и Promise для того же ключа, если вы используете Promise[_];Вы можете иметь, например, Task[Int] и Promise[String], и в этом случае p complete task.result не имеет смысла. Но, честно говоря, я бы сказал, что в этом случае то, что у вас есть, является в значительной степени лучшим, что вы можете сделать (без значительного изменения дизайна) по двум причинам:

  1. Future является ковариантнымпоэтому Future[_] в основном эквивалентно Future[Any].

  2. если задача существует и завершена, я немедленно возвращаю результат, в противном случае даю обещание

    Если задача не существует, выполнитеу вас есть способ узнать, каким будет его параметр типа?

...