Skip to content

Feature request: an equivalent to Lwt.npick #558

@SGrondin

Description

@SGrondin

Motivation

Under Fiber.first:

Warning: it is always possible that both operations will succeed (and one result will be thrown away). This is because there is a period of time after the first operation succeeds, but before its fiber finishes, during which the other operation may also succeed.

This enables Fiber.first to have a nice, convenient API. 98% of the time, I do not care about the edge case, so the benefits of the API are worth the downside explained in the warning.

But 2% of the time, I do care about the return value of the second fiber that may also have succeeded.

Comparison: Lwt

Lwt.pick

Lwt.pick : ('a Lwt.t) list -> 'a Lwt.t

This function is roughly equivalent to Fiber.any.

Lwt.pick ps returns a promise that is pending until one promise in the list ps becomes resolved.
When at least one promise in ps is resolved, Lwt.pick tries to cancel all other promises that are still pending, using Lwt.cancel.

Lwt.npick

Lwt.npick : ('a Lwt.t) list -> ('a list) Lwt.t

Lwt.npick ps is similar to Lwt.pick ps, the difference being that when multiple promises in ps are fulfilled simultaneously (and none are rejected), the result promise is fulfilled with the list of values the promises were fulfilled with.
When at least one promise is rejected, Lwt.npick still rejects the result promise with the same exception.

Draft idea

We're optimizing for the 2% case here. Something that behaves just like Fiber.first, but without losing the second successful result (when it succeeds """at the same time""").

Fiber.n_first : (unit -> 'a) -> (unit -> 'a) -> [ `Left of 'a | `Right of 'a | `Both of 'a * 'a ]
Fiber.n_any : (unit -> 'a) list -> 'a list

The way Lwt accomplishes this is by scanning the list for other successful promises before resolving the returned promise.

I had a quick look at the code and it seems doable.

Is this a feature the maintainers would welcome?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions