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