Thank you!

Tejas notrealemail at gmail.com
Wed Sep 8 06:03:49 UTC 2021


On Wednesday, 8 September 2021 at 05:07:03 UTC, Ali Çehreli wrote:
> On 9/7/21 9:36 PM, Tejas wrote:
>
> >>> S _s;
> >>>
> >>> S s() {return _s;}
>
> [...]
>
> > Do you really think people who are writing code like that
> expect a
> > temporary to be generated?
>
> I think so. Even if they don't, I can't imagine this being a 
> big surprise in the future; a little test would reveal that _s 
> was not changing.
It's not a big surprise, I agree; but it _is_ a gotcha.

>
> > What else could be the purpose of returning
> > an existing struct and using it as an `lvalue` if not to
> modify it?
>
> The returned copy is not an lvalue; it is an rvalue.

Yes, it is an rvalue, which is then assigned to a temporary and 
then that temporary is used as an `lvalue`
```d
auto __temp = s();
__temp.i = 42; //this is what is happening behind the scenes, 
according to my knowledge
```
But the user might be thinking that they're modifying `_s`, not 
some intermediate temporary.
Again, it can easily be figured out via a small test, so not a 
very big deal, but could be a little annoying to discover at 
runtime.

>
> > I feel we would be better off if the same
> > ```d
> > <your_var_name> is not an lvalue and cannot be modified
> > ```
>
> rvalues cannot be assigned to

Which is exactly what the original code is doing.

>  but they can be modified.

I agree; you taught me that previously in an operator overloading 
thread :)


> How? Being value types, structs are consistently passed and 
> returned by value. Otherwise, we wouldn't be able to write a 
> factory function:
>
> S makeS() {
>   return S();  // Should this be returning a reference to a 
> temporary?
> }

No, it should return by value, but you  wouldn't use it as
```d
makeS().i = 100;
```

And then expect `makeS().i == 100` to be true, would you?

My problem is that the original code returned an _existing_ 
`struct`, which implies that the struct itself is being returned, 
not a duplicate of it(even though after one understands that 
`structs` are value types they'll start using `ref S` instead of 
`S`).

I'm not saying a function that returns a `struct` should return 
the struct by reference; but if that function is being used in 
the left hand side of an assignment statement _and_ it is 
returning a **named** value(`_s` here), I think its reasonable 
for the compiler to at least emit a warning that the value 
returned by the function is not usable beyond the scope of that 
statement.


And if none of the above convinces anyone

```d
int integer;
int func(){
     return integer;
}
void main(){
     func() = 30;
}
Output:
onlineapp.d(29): Error: `func()` is not an lvalue and cannot be 
modified
```

Please allow this to compile.
`int` is value type, so it is fine to generate a temporary and 
allow the code to compile, right? A small test will reveal that 
`integer` is not being modified, so it's not **that** big of a 
deal, right?


More information about the Digitalmars-d mailing list