RfC for language feature: rvalue struct

FeepingCreature feepingcreature at gmail.com
Wed Jan 25 16:23:51 UTC 2023


Before I take on the effort of writing up and submitting a DIP, 
let me solicit feedback and see if anyone can see a reason why 
this idea is dumb and doesn't work.

tl;dr: `immutable struct` was a mistake: it's too weak. `rvalue 
struct` is what we really want.

# aside: what are lvalues and rvalues

lvalue: an expression that has an address.
rvalue: an expression that does not.

The names come from `a = b`: an "lvalue" (left value) is a thing 
that can appear on the left of the equals sign, an "rvalue" 
(right value) may only appear on the right.

Example: `int a` is an lvalue. `5` is an rvalue. You can write `a 
= 5` but not `5 = a`.

# rvalue struct

This is a summary of an idea from my DConf talk 
https://www.youtube.com/watch?v=eGX_fxlig8I

I'm writing it up because I'm noticing that the `immutable` bugs 
are neverending and the workarounds are an endless hole into 
which effort and nerves are thrown to no perceivable change.

What is it? Take this struct

```
rvalue struct S
{
   int a;
   int[] b;
}
```

Two rules:

1. A `rvalue` struct has `immutable` fields.
   `typeof(s)` is `S`, but `typeof(s.b)` is `immutable int[]`.
2. Any symbol that would be an lvalue to *a field of `S`* is 
instead an rvalue.

That's it.

What is the effect of this?

This works:

```
S foo(S s) {
   S value = S.init;
   value = s;
   *&value = s;
   return s;
}
```

This does not:

```
S s;
s.a = 5;
&s.a
((ref int i) {})(s.a);
```

Note that you can overwrite `value` all you want. You can take 
the address of `value`. It's not immutable. But its fields are 
immutable. Isn't that a problem? No: because its fields *don't 
exist.* They're rvalues. You can't address them, you can't 
reference them. You can never observe a constness violation on 
them, because you can only observe them as rvalues. `s.a` is 
effectively an accessor.

# What's the use?

D libraries like to behave like they can declare variables and 
assign values to them. (Oh, to live in such innocence!) This is 
all over Phobos, Dub, etc. `immutable struct` frustrates this 
belief. Because you could always take the address of a field, 
which would be `immutable T*`, you could see the value changing 
when you overwrite the variable - a constness violation. 
`immutable` solves this by preventing you from modifying the 
memory of the field while the pointer lives. This largely doesn't 
work, because people don't test with `immutable struct` in the 
first place. If an `rvalue struct` is used, the naive code works 
as before, but the type gets the correctness benefits of 
immutable: you can only construct a new value through the 
constructor.

# Corporate Motivation

Some details about Funkwerk, fresh off `wc -l`: In the modern 
part of our codebase, we have 648 domain structs, out of which 
278 are `immutable struct`, and at least another 129 are good 
candidates to make immutable. In those 113kloc, we have **no** 
pointers to struct fields. None. `immutable struct` puts on the 
language, on library developers and on end users, immense 
difficulty and effort to protect a usecase that isn't useful.


More information about the Digitalmars-d mailing list