Skip to content

Variants - Simplified #1859

@rgrinberg

Description

@rgrinberg

Variants - Simplified

(This proposal is aimed at @TheLortex who has expressed some interest in implementing this feature. However, some details need to be hashed between the maintainers first)

Now that we've merged virtual libraries, we can consider implementing the full
variants proposal. It's heavily simplified from the original proposal so I'm
rewriting the original ticket.

TL;DR:

Variants are now tags that are attached to implementations. Executables may now
select groups of implementations simultaneously by choosing such tags.

Implementation Steps

  1. Modify the library stanza to allow marking library implementations with an
    optional (variant ..) field.

  2. Modify the executables stanza to allow for a (variants ..) field. It should
    allow for a list of tags to be selected.

  3. Modify the dune-pacakge format accordingly to maintain variant information
    for implementations.

  4. When loading the library database, we must maintain a map from individual
    variants to a map of virtual libraries to implementations. The next step
    will make it obvious why we need such a data structure.

  5. When calculating the closure for linking (executables), we now need to select
    implementations based on the set of tags. I'll describe this in a bit more
    detail

Roughly, the closure pipeline for executables would look like:

deps
(* (1) calculate the closure *)
|> closure
... (* (2) *)
(* (3) verify that there's an implementation present for every vlib
  and make sure the linking order is correct *)
|> Virtual_libs.associate

In ..., we'd like to insert a step that would insert implementations based on
the selected set of variants.

So essentially:

val add_impls_for_variants : Lib.t list -> variants:Variant.t list -> Lib.t list

Now there's a bit of a problem here: we must calculate the closure again after
this step, and recursively do (1; 2) until 2. doesn't change the closure.
This is because an implementation itself may depend on a virtual library.

Consider:

(library
 (name bar)
 (virtual_modules bar))
 
(library
 (name baz_js)
 (implements bar)
 (variant js))

(library
 (name foo)
 (virtual_modules foo))
 
(library
 (name foo_js)
 (libraries bar)
 (variant js)
 (implements foo))
 
(executable
 (name x)
 (libraries foo)
 (variants js))

Now, if we calculate the closure of x we'll discover foo and that we need
the foo_js library. But now we'll also need to select the correct
implementation for bar.

Taking the closure + finding implementations in a fixpoint doesn't seem very
attractive, so unless @diml has a better idea, I suggest we interleave the
variant-based implementation selection with the closure itself. In this new
closure, we'll check if the current library is virtual, and we have an
implementation for it based on the set of variants present. In this case, we'll
just add the correct implementation to the closure directly.

Possible Issues & Future Work

  • As usual, making decent error messages always increases the difficulty. Let's
    worry about this once we have a prototype ready. We can threw some test cases
    and improve errors from there.

  • Since variant tags is going to be quite small (compared to the set of
    libraries at least), We might need a conflict resolution mechanism when two
    libraries provide an implementation for the same library with the same variant
    name. Yes, in this case the user can always just drop variants altogether and
    go back to concrete implementations, but that's a bit dissapointing.

    Perhaps one could resolve this ambiguity by providing a concrete
    implementation in the libraries field for the executable. So when doing
    lookups from 4, we'll keep in mind the list of libraries the user actually
    listed.

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