DIP proposal: Enum parameters
Quirin Schroll
qs.il.paperinik at gmail.com
Mon Sep 26 08:57:42 UTC 2022
On Friday, 23 September 2022 at 17:54:49 UTC, Paul Backus wrote:
> On Friday, 23 September 2022 at 15:41:21 UTC, Quirin Schroll
> wrote:
>> Read the draft here:
>> https://github.com/Bolpat/DIPs/blob/EnumParameters/DIPs/1NNN-QFS.md
>>
>> Feedback is welcome.
>
> Some thoughts.
>
> * Does this need `__traits(isEnum)` (like `__traits(isRef)`)
> for working with `auto enum` parameters?
Good catch, `__traits(isEnum)` does not exist currently. But it
makes sense to add it, not only for this proposal, but generally.
I’ll add that.
> * Sometimes library authors prefer to have a parameter passed
> at runtime even when it *could* be passed at compile time, to
> avoid template bloat. So for use cases like `format` and
> `regex`, this proposal is not a clear win.
Is that the case? Of course, you get *one* additional template
instantiation for regex because it normally is not a template at
all. `format` is already a template; with a template argument
format, you ideally only get a different instantiation. A high
number of template instances is usually only a problem if the
templates are recursive. If it happens to be a problem, one can
always put the format or regex in a local variable and use that.
This workaround is harder if you also want the value to be an
rvalue; you’ll then need to define a function that returns the
value *and* takes a run-time value as a parameter (that it won’t
actually use) so that CTFE is out of the picture.
This is a niche case; I guess it’s okay for this to be a little
work.
> * A significant chunk of the proposed use-cases could also be
> addressed by adding `opStaticIndex`. Probably worth mentioning
> in the "Alternatives" section.
I wrote a draft for static indexing. There, I mentioned that
something like this, i.e. a feature to pass parameters at
compile-time were added, it would supersede the proposal. I
figured that it was actually easier to specify and explain
compile-time parameter passing than static indexing.
Static indexing with a completely separate set of operators
almost doubles the jungle of indexing operators and is very
specific.
> * Incompatibility with other parameter storage classes is a
> design smell. Ideally, we would like our language features to
> be orthogonal and work together with each other.
Maybe you got this wrong. It is not that by virtue of `enum` any
thinkable parameter storage class would be incompatible. It is
just that all of the existing ones are.
`enum` is a stronger form of `in` and thus is in the same group
with `in`, `out`, and `ref`, which specify parameter passing. Two
of them together would have a very specific meaning and not
simply the rules for both because that would be contradictory.
Let’s go through [the
list](https://dlang.org/spec/function.html#ParameterStorageClass):
* `auto` can only be used in conjunction with `ref` to form `auto
ref`. Alone, it is invalid.
* `TypeCtor` are allowed. It says so in the DIP.
* `final` as far as I know is only there to generate a specific
error; it is never valid.
* `in` (see below)²
* `lazy` makes no sense; the value is already produced at
compile-time.
* `out` is incompatible with `enum` because `enum` values are
never lvalues and cannot be written to.
* `ref` is incompatible with `enum` because `enum` values are
never lvalues.
* `return` is really only something for run-time values.¹
* `scope` is really only something for run-time values.¹
¹ To be honest, I don’t know how `scope` and by extension
`return` would apply to compile-time constants. If I’m not
mistaken, life-time of those objects is infinite.
² The `in` storage class means `const scope` and maybe `ref`.
`enum` is incompatible with `ref`, `scope` does not apply.
> * Similarity to `ref` is also a design smell. `ref` is badly
> designed, and things like `auto ref` and
> `core.lifetime.forward` exist entirely to work around its
> deficiencies. We should avoid making the same mistake twice.
I see how `auto ref` has flaws because the value category is not
preserved, i.e. the parameter is an lvalue regardless whether it
was initialized by an rvalue or lvalue. This is where the analogy
parts. An `auto enum` parameter initialized by a compile-time
constant is a compile-time constant and an `auto enum` parameter
initialized by a run-time value is a run-time value. Nothing has
to be done to forward.
The analogy is limited to the way overloading and inference on
the category (value category for `ref` and compile-time category
for `enum`) works.
> […] I can see situations where this would be useful, but I'm
> not convinced it's useful *enough* to justify the
> language-complexity and maintenance costs.
That’s what I’m trying to find out.
More information about the Digitalmars-d
mailing list