`@rvalue ref` and `@universal ref`
Quirin Schroll
qs.il.paperinik at gmail.com
Wed Aug 7 10:45:55 UTC 2024
On Wednesday, 7 August 2024 at 03:47:24 UTC, IchorDev wrote:
> On Tuesday, 6 August 2024 at 15:26:49 UTC, Quirin Schroll wrote:
>> On Monday, 29 July 2024 at 05:52:40 UTC, IchorDev wrote:
>>> Also I’m not sure about the at-attribute-based syntax. It
>>> makes the feature feel like an afterthought, even though this
>>> functionality is very useful. Perhaps a better solution
>>> syntax-wise could be to use `in` as the ‘rvalue’ attribute,
>>> and `auto in` could be the ‘universal’ attribute. So then:
>>> - `@rvalue` —> `in`
>>> - `@rvalue ref` —> `in ref`
>>> - `@universal ref` —> `auto in ref`
>>> - `@universal auto ref` —> `auto in auto ref`
>>
>> The issue is, it can’t be done anymore. For all the time it
>> was there, `in` meant `const`.
>
> And it still does. Just this week I’ve had to dissuade two
> people from using `in` instead of `const`.
The issue is, if we make `in` mean something that doesn’t include
`const`, it’ll be confusing for the simple reason of what it
meant since forever and what it’s supposed to be.
>> Also, and this is the key killer: Conceptually, `in` means
>> input parameter, i.e. something that supplies your function
>> with data to make decisions on, call it configuration if you
>> like
>
> This meaning is nebulous at best. What would we actually make
> `in` *do* to have it make parameters inputs? `-preview=in`
> making `in` into `scope ref const` that binds to rvalues is
> just as related to a parameter being an input as `in` binding
> to rvalues in general is.
I can only say that I disagree. An input parameter is for the
function to only take information from to base decisions on.
Everything it is follows logically from that:
- Can’t mutate it.
- Can’t escape it.
- Can bind it in any way it likes (by reference or by value).
If `in` binds rvalues so that they’re being moved from, it’s
basically the opposite of an input parameter.
Of course, there could be a different meaning of “input” in the
sense that it goes in and never gets out, but that was never
intended.
>> and this is what informed the `-preview=in` semantics.
>
> And time has proven that `-preview=in` is:
> 1. never going to become the default; and
> 2. is too limiting to even be very useful.
>
> Your DIP would make `-preview=in` an obsolete dinosaur, so just
> replace it.
Preview-`in` gives you an optimization based on the size of the
type. `@universal ref` wouldn’t do that.
The reason it’s behind a preview switch is the same reason as
`fieldwise`, `fixAliasThis`, `nosharedaccess`,
`inclusiveincontracts`, and `fixImmutableConv` are: They are
breaking changes and some silently change behavior.
If you have a `@system` function that uses an `in` slice
parameter, with `-preview=in`, that parameter becomes `scope`,
but unchecked. With `DIP1000`, a caller that passes a literal can
allocate the literal on the stack and that introduces a bug.
My bet is that all but `rvaluerefparam` are going to be the
default in the next Edition.
>> Another aspect I don’t like stylistically, is `auto in`. As a
>> parameter storage class, `auto` means infer and requires
>> templates, plus one could introspect what the inference
>> determined.
>
> Is that a huge problem? You could always try suggest a better
> syntax for that case though, I was just invoking a recognisable
> idiom.
>
>> Contrary to that, `@universal` requires materializing rvalues.
>> Essentially, binding `arg` to a `@universal ref` parameter
>> would be exactly like passing `arg.materializeU.value` to a
>> `ref` parameter, and likewise passing `arg.materializeR.value`
>> for binding to an `@rvalue ref` parameter.
>
> I think you should try rephrasing this because it doesn’t make
> sense.
“Contrary to that, `@universal` requires materializing rvalues.
Essentially, binding `arg` to a `@universal ref` parameter
would be exactly like passing `arg.materializeU.value` to a
`ref` parameter. Binding `arg` to an `@rvalue ref` would be
exactly like passing passing `arg.materializeR.value` for binding
to to a `ref` parameter.”
>>> This way it’s […] shorter to write
>>
>> That I consider the wordiness a win[sic]. Not only is it
>> clearer […]
>
> It’s harder to read more text, particularly when it overflows
> the available horizontal space. It’s not ‘clearer‘ at all.
>
>>> […] [A]nd we can **finally** make `in` do something useful by
>>> default.
>>
>> But `-preview=in` already does that.
>
> `-preview=in` is not the default. Saying that ‘as long as you
> change the defaults, the defaults are good’ is misleading.
> `-preview=in` is not the default.
I don’t understand what you’re meaning here.
> No matter how we move forwards with `in`, something is going to
> break;
Not with Editions. The whole idea of Editions is that an Edition
is a set of Previews that are enabled together, and that modules
opt into an Edition. Because every Edition starts with zero code
written for it, it can’t break code.
> but I think making `in` a useful feature instead of
> dead-on-arrival would be a welcome change rather than a
> disappointing one.
The reason `in` isn’t useful as-is is because it’s just `const`
and `const` isn’t that much longer than `in` while both being
clear and not having a preview that is likely to change its
semantics.
The reason `in` isn’t useful in Preview is because almost no-one
uses this preview switch. It’s kind of niche, and most code works
great without it. The difference between `scope const`
pass-by-value and `in` (under preview) is an optimization in
almost all cases (aliasing is the exception), and if a type is
small, it’s not even that. Also, preview-`in` is actively
dangerous with DIP1000 unless `@safe` isn’t the default.
More information about the dip.ideas
mailing list