Thread overview
Structs by ref in D2
Aug 20, 2009
bearophile
Aug 21, 2009
Jesse Phillips
Aug 21, 2009
Lutger
Aug 21, 2009
Daniel Keep
Aug 21, 2009
bearophile
Aug 21, 2009
Daniel Keep
Aug 21, 2009
bearophile
Aug 22, 2009
Daniel Keep
August 20, 2009
This post is about D2 compiler/language.
Is the following code supposed to be wrong in D2? (and if so, then why?)

import std.c.stdio: printf;

struct S { int x, y; }

S produce() {
    S s = S(10, 20);
    return s;
}

void show(ref S s) {
    printf("%d %d\n", s.x, s.y);
}

void main() {
    show(produce());
}


That code works in D1.042, while DMD V.2.031 gives the errors:
test.d(10): Error: function temp.show (ref S s) does not match parameter types (S)
test.d(10): Error: produce() is not an lvalue


After a gentle suggestion by Kirk McDonald I have also tried the following signatures, with similar error messages:
void show(ref const(S) s) {
void show(const ref S s) {

passing locally-defined structs by ref is handy (the LDC compiler is currently able to do it, as older D1 compilers too).

Bye,
bearophile
August 21, 2009
On Thu, 20 Aug 2009 18:15:07 -0400, bearophile wrote:

> This post is about D2 compiler/language. Is the following code supposed to be wrong in D2? (and if so, then why?)
> 
> import std.c.stdio: printf;
> 
> struct S { int x, y; }
> 
> S produce() {
>     S s = S(10, 20);
>     return s;
> }
> 
> void show(ref S s) {
>     printf("%d %d\n", s.x, s.y);
> }
> 
> void main() {
>     show(produce());
> }
> 
> 
> That code works in D1.042, while DMD V.2.031 gives the errors:
> test.d(10): Error: function temp.show (ref S s) does not match parameter
> types (S) test.d(10): Error: produce() is not an lvalue
> 
> 
> After a gentle suggestion by Kirk McDonald I have also tried the
> following signatures, with similar error messages: void show(ref
> const(S) s) {
> void show(const ref S s) {
> 
> passing locally-defined structs by ref is handy (the LDC compiler is currently able to do it, as older D1 compilers too).
> 
> Bye,
> bearophile

Note that I don't know much about what I'm saying :)

This is probably related to an early conversation, not sure which one, but if I recall correctly this is supposed to be an error.

The problem is that produce() is returning a temporary variable which would have no affect if modified. The idea is that such modification is unintended and should be flag as an error.

If you are interested in performance than I'd think void show(const S s) should be reasonable, but that could have threading issues if the compiler makes it a reference.
August 21, 2009
By const ref seems reasonable to allow, but by ref is bug prone. Why is it handy?

August 21, 2009

Lutger wrote:
> By const ref seems reasonable to allow, but by ref is bug prone. Why is it handy?

struct Vector4
{
    float[4] xyzw;
    Vector opAdd(ref Vector rhs);
}

Vector code can be made much faster using ref arguments, but if you use ref arguments, you can't have anything more complex than a single binary expression.

D's stance at the moment seems to be: "speed, convenience: pick one"

/sadface
August 21, 2009
Daniel Keep:

>Vector code can be made much faster using ref arguments,<

You are right regarding DMD (that's what I was asking for), but LDC often is able to inline everything (if the method is short), so using ref leads to the same (high) performance.

Bye,
bearophile
August 21, 2009
On Fri, 21 Aug 2009 10:42:08 -0400, Daniel Keep <daniel.keep.lists@gmail.com> wrote:

>
>
> Lutger wrote:
>> By const ref seems reasonable to allow, but by ref is bug prone. Why is it
>> handy?
>
> struct Vector4
> {
>     float[4] xyzw;
>     Vector opAdd(ref Vector rhs);
> }
>
> Vector code can be made much faster using ref arguments, but if you use
> ref arguments, you can't have anything more complex than a single binary
> expression.

Hence why const ref is reasonable:

Vector opAdd(ref const Vector rhs) const;

The issue is possibly with ref.  There are two reasons to use ref, 1 is to be able to change the data referenced, 2 is for passing speed.

1 is bad for rvalues.  2 should be ok for rvalues.

If there was a way to signify you only want to use ref for reason 2, there would be a good solution.  Most of the time, that's const ref, but what you really want is head-const ref, which isn't currently possible.  If a struct has references to other values, they might be lvalues, and you may want to be able to change them.

I'm uncertain as to how often you would want to pass an rvalue as a ref that had lvalue reference in it, but at the very least, ref const should be valid.

-Steve
August 21, 2009

Steven Schveighoffer wrote:
> ...
> 
> The issue is possibly with ref.  There are two reasons to use ref, 1 is to be able to change the data referenced, 2 is for passing speed.
> 
> 1 is bad for rvalues.  2 should be ok for rvalues.
> 
> If there was a way to signify you only want to use ref for reason 2, there would be a good solution.  Most of the time, that's const ref, but what you really want is head-const ref, which isn't currently possible. If a struct has references to other values, they might be lvalues, and you may want to be able to change them.
> 
> I'm uncertain as to how often you would want to pass an rvalue as a ref that had lvalue reference in it, but at the very least, ref const should be valid.
> 
> -Steve

In my own code, I usually record my intent by using "inout" for variables I intend to modify and "ref" for ones which I don't.

Always seemed reasonable to me.
August 21, 2009
Daniel Keep:
> In my own code, I usually record my intent by using "inout" for variables I intend to modify and "ref" for ones which I don't. Always seemed reasonable to me.

for the compiler they mean the same thing, but inout is being deprecated.

Bye,
bearophile
August 22, 2009
bearophile wrote:
> Daniel Keep:
>> In my own code, I usually record my intent by using "inout" for variables I intend to modify and "ref" for ones which I don't. Always seemed reasonable to me.
> 
> for the compiler they mean the same thing, but inout is being deprecated.
> 
> Bye,
> bearophile

I realise this.  My point is that the two keywords pretty nicely sum up a difference in intent.