www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Structs by ref in D2

reply bearophile <bearophileHUGS lycos.com> writes:
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
Aug 20 2009
next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
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.
Aug 20 2009
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
By const ref seems reasonable to allow, but by ref is bug prone. Why is it 
handy? 
Aug 21 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
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
Aug 21 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
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
Aug 21 2009
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Aug 21 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
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.
Aug 21 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
Aug 21 2009
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
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.
Aug 22 2009