Related to the matter of linkage, I've been ruminating a bit on the current limited support for compile-time constants.

The "items" in a rust module are currently functions, iterators, types, and sub-modules. These are constants, in a way, but they're not the sort a lot of people think of. In particular there are no "value-like" constant items such as numbers, strings, vectors, records, tuples. They can only be dynamic values. If you want to produce one of these -- even if it's always the same value -- you have to write a function that returns it.

This is not entirely pleasant. There is room for improvement:

  - Things that *could* be compile-time constants can't be calculated
    "once". We wind up putting code in the executable rather than
    read-only data, and re-calculating repeatedly at runtime.

  - Some values -- say, 0-ary tags -- wind up as functions even
    though they'd make more sense as enum-like constant values.

  - Constant-folding is left, at best, to optional compiler passes. It
    might be nice to be able to guarantee a certain quantity of it to
    language users, done in the front-end.

Suppose, instead, that we have an item type

      'const <ty> <ident> = <const-expr>;'

and we recursively define a subset of the expr grammar as const-ness-propagating. And we're careful to be sure we mean *compile-time* constant, not initialization-time constant a la C. Then:

  - The problems above are solved. Enum-like 0-ary tags turn into
    consts. Big structured consts can be calculated at compile time
    and stored read-only. Constant folding through arithmetic and such
    can be guaranteed to some reasonable degree.

  - A few syntactic contexts (linkage-names in native modules, say)
    currently take literal values, but could be generalized to take
    references to constants. This could potentially wind up as a sort
    of "cheapest layer" of static metaprogramming (not getting into
    actual AST-splicing or anything).

  - We already have the concepts of immutability and pure functions,
    it seems a bit of a shame not to permit their use at compile time
    for complicated constants.

Of course, there are also reasons to be wary of this:

  - Read-only memory has the problem of not being very amenable to
    refcounting. We could steal a tag-bit on pointers to read-only
    values, but then we would not be tracking their refcount at all,
    and this would further seal the fate of crate-loading as an
    irrevocable action within a given process domain (see note on this
    in previous email regarding linkage; we may be going that route
    anyways).

  - Value-level equality needs to be preserved and/or checked somehow
    between compile-time and load-time, rather than just type
    compatibility. Compiling a crate with math.pi = 3.14, then finding
    you linked against a recompiled crate with math.pi = 3.15, is an
    unwelcome situation. We'd need some kind of scheme to guard against
    this, or make users somehow aware of the risks. Possibly just
    require compilation-unit UUID-identity or CHF-identity if there's
    been any constant folding? Or track the constants that were folded
    and check equality at runtime link time? Awkward options, all...

Any thoughts?

-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to