www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - pass by reference parameters

reply imr1984 <imr1984_member pathlink.com> writes:
ok i asked about this before and i was told that if you pass a large struct
parameter by value, the compiler will optomize it to pass by ref if it finds
that the function doesnt change the function param. Is this absolutely certain?
I often find myself worrying if thats actually the case and just pass a pointer
to the struct like i did when using C.
May 20 2004
parent reply "Achilleas Margaritis" <axilmar b-online.gr> writes:
"imr1984" <imr1984_member pathlink.com> wrote in message
news:c8inrv$13jl$1 digitaldaemon.com...
 ok i asked about this before and i was told that if you pass a large

 parameter by value, the compiler will optomize it to pass by ref if it

 that the function doesnt change the function param. Is this absolutely

 I often find myself worrying if thats actually the case and just pass a

 to the struct like i did when using C.

I think you better pass it with a pointer. I don't think it is possible for a compiler to fully understand how things are used...it may be the case that the struct is implicitely modified in a set of deeply nested functions. I think the variable passing semantics of D are weird: it is a mixture of C (not C++!) and Java: from one hand, we have pointers and structures and the C world, from the other hand, we have Java with references. I wish it as simpler, as in C++: pass by reference, pass by value, independently of the data type.
May 22 2004
next sibling parent imr1984 <imr1984_member pathlink.com> writes:
yeah i agree with you. Walter would you like to comment on this ? This really
needs to be more clearly documented in the spec.

In article <c8nldq$slf$1 digitaldaemon.com>, Achilleas Margaritis says...
"imr1984" <imr1984_member pathlink.com> wrote in message
news:c8inrv$13jl$1 digitaldaemon.com...
 ok i asked about this before and i was told that if you pass a large

 parameter by value, the compiler will optomize it to pass by ref if it

 that the function doesnt change the function param. Is this absolutely

 I often find myself worrying if thats actually the case and just pass a

 to the struct like i did when using C.

I think you better pass it with a pointer. I don't think it is possible for a compiler to fully understand how things are used...it may be the case that the struct is implicitely modified in a set of deeply nested functions. I think the variable passing semantics of D are weird: it is a mixture of C (not C++!) and Java: from one hand, we have pointers and structures and the C world, from the other hand, we have Java with references. I wish it as simpler, as in C++: pass by reference, pass by value, independently of the data type.

May 22 2004
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Achilleas Margaritis wrote:

<snip>
 I think you better pass it with a pointer. I don't think it is 
 possible for a compiler to fully understand how things are used...it 
 may be the case that the struct is implicitely modified in a set of 
 deeply nested functions.

D is supposed to minimise the need for explicit pointer uses. Mabye we could implement copy on write here. Structs passed by reference, but if the function changes the value, it would make a copy of it and use that instead. The only thing is that all modules would need to be compiled with the same convention for it to work. (Hence upgrading/changing your compiler and/or its options would necessitate a clean and rebuild.) And when you get into libs, it opens a whole new can of worms.... Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
May 24 2004
parent reply imr1984 <imr1984_member pathlink.com> writes:
I think D needs a 'ref' keyword like C# has. This way large structs can be
passed by reference without nasty pointers. The way i see it, this is the only
way to support this because as Stewart says if you have a function exported from
a library, and it takes a struct, the only way for the compiler to know that the
exported func takes the struct by Ref is if its indicated in the prototype with
the ref keyword.

In article <c8sgn9$1ocs$1 digitaldaemon.com>, Stewart Gordon says...
Achilleas Margaritis wrote:

<snip>
 I think you better pass it with a pointer. I don't think it is 
 possible for a compiler to fully understand how things are used...it 
 may be the case that the struct is implicitely modified in a set of 
 deeply nested functions.

D is supposed to minimise the need for explicit pointer uses. Mabye we could implement copy on write here. Structs passed by reference, but if the function changes the value, it would make a copy of it and use that instead. The only thing is that all modules would need to be compiled with the same convention for it to work. (Hence upgrading/changing your compiler and/or its options would necessitate a clean and rebuild.) And when you get into libs, it opens a whole new can of worms.... Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.

May 24 2004
next sibling parent "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
I ran into a similar problem over here: news:c66dlu$1mt7$1 digitaldaemon.com

- Kris

"imr1984" <imr1984_member pathlink.com> wrote in message
news:c8tbvq$fm$1 digitaldaemon.com...
 I think D needs a 'ref' keyword like C# has. This way large structs can be
 passed by reference without nasty pointers. The way i see it, this is the

 way to support this because as Stewart says if you have a function

 a library, and it takes a struct, the only way for the compiler to know

 exported func takes the struct by Ref is if its indicated in the prototype

 the ref keyword.

 In article <c8sgn9$1ocs$1 digitaldaemon.com>, Stewart Gordon says...
Achilleas Margaritis wrote:

<snip>
 I think you better pass it with a pointer. I don't think it is
 possible for a compiler to fully understand how things are used...it
 may be the case that the struct is implicitely modified in a set of
 deeply nested functions.

D is supposed to minimise the need for explicit pointer uses. Mabye we could implement copy on write here. Structs passed by reference, but if the function changes the value, it would make a copy of it and use that instead. The only thing is that all modules would need to be compiled with the same convention for it to work. (Hence upgrading/changing your compiler and/or its options would necessitate a clean and rebuild.) And when you get into libs, it opens a whole new can of worms.... Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.


May 24 2004
prev sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"imr1984" <imr1984_member pathlink.com> escribió en el mensaje
news:c8tbvq$fm$1 digitaldaemon.com
| I think D needs a 'ref' keyword like C# has. This way large structs can be
| passed by reference without nasty pointers. The way i see it, this is the
only
| way to support this because as Stewart says if you have a function
exported from
| a library, and it takes a struct, the only way for the compiler to know
that the
| exported func takes the struct by Ref is if its indicated in the prototype
with
| the ref keyword.
|

What's wrong with inout?

-----------------------
Carlos Santander Bernal
May 24 2004
next sibling parent reply "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
One cannot use 'inout' with a const struct, since by definition it's
read-only.

- Kris

"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:c8udnv$205u$1 digitaldaemon.com...
 "imr1984" <imr1984_member pathlink.com> escribió en el mensaje
 news:c8tbvq$fm$1 digitaldaemon.com
 | I think D needs a 'ref' keyword like C# has. This way large structs can

 | passed by reference without nasty pointers. The way i see it, this is

 only
 | way to support this because as Stewart says if you have a function
 exported from
 | a library, and it takes a struct, the only way for the compiler to know
 that the
 | exported func takes the struct by Ref is if its indicated in the

 with
 | the ref keyword.
 |

 What's wrong with inout?

 -----------------------
 Carlos Santander Bernal

May 24 2004
parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Then this boils down to the good old war about "const". Walter decided to
make "const" a storage class, not a type modifier. This means, we have
const objects, you can take a pointer from them, but then the compiler does
not help you in tracking that they were const.

Introducing "ref" in addition to "inout" would just hide this fact in a very
obscure way. "inout mytype arg" would be "mytype &arg" in C++, while "ref
mytype arg" would be "const mytype &arg".

I believe that whole business of "in", "out" and "inout" arguments is
flawed. My first expectation, when I saw these was, that that they are
"copy-in/copy-out" arguments. The specs are not very precise when they talk
about this question. Somehow, I have the feeling, that D tries to hide the
complexity of reference/value arguments from the user, but, at the same
time, obscures and cripples the concept completely.

My opinion: neither the C++ nor the D way are the solution. I don't know the
solution, but it has to be out there somewhere.



Kris wrote:

 One cannot use 'inout' with a const struct, since by definition it's
 read-only.
 
 - Kris
 
 "Carlos Santander B." <carlos8294 msn.com> wrote in message
 news:c8udnv$205u$1 digitaldaemon.com...
 "imr1984" <imr1984_member pathlink.com> escribió en el mensaje
 news:c8tbvq$fm$1 digitaldaemon.com
 | I think D needs a 'ref' keyword like C# has. This way large structs can

 | passed by reference without nasty pointers. The way i see it, this is

 only
 | way to support this because as Stewart says if you have a function
 exported from
 | a library, and it takes a struct, the only way for the compiler to know
 that the
 | exported func takes the struct by Ref is if its indicated in the

 with
 | the ref keyword.
 |

 What's wrong with inout?

 -----------------------
 Carlos Santander Bernal


May 24 2004
next sibling parent Derek Parnell <derek psych.ward> writes:
On Tue, 25 May 2004 08:44:21 +0200, Norbert Nemec wrote:

 Then this boils down to the good old war about "const". Walter decided to
 make "const" a storage class, not a type modifier. This means, we have
 const objects, you can take a pointer from them, but then the compiler does
 not help you in tracking that they were const.
 
 Introducing "ref" in addition to "inout" would just hide this fact in a very
 obscure way. "inout mytype arg" would be "mytype &arg" in C++, while "ref
 mytype arg" would be "const mytype &arg".
 
 I believe that whole business of "in", "out" and "inout" arguments is
 flawed. My first expectation, when I saw these was, that that they are
 "copy-in/copy-out" arguments. The specs are not very precise when they talk
 about this question. Somehow, I have the feeling, that D tries to hide the
 complexity of reference/value arguments from the user, but, at the same
 time, obscures and cripples the concept completely.
 
 My opinion: neither the C++ nor the D way are the solution. I don't know the
 solution, but it has to be out there somewhere.

See below ...
 Kris wrote:
 
 One cannot use 'inout' with a const struct, since by definition it's
 read-only.
 
 - Kris
 
 "Carlos Santander B." <carlos8294 msn.com> wrote in message
 news:c8udnv$205u$1 digitaldaemon.com...
 "imr1984" <imr1984_member pathlink.com> escribió en el mensaje
 news:c8tbvq$fm$1 digitaldaemon.com
 | I think D needs a 'ref' keyword like C# has. This way large structs can

 | passed by reference without nasty pointers. The way i see it, this is

 only
 | way to support this because as Stewart says if you have a function
 exported from
 | a library, and it takes a struct, the only way for the compiler to know
 that the
 | exported func takes the struct by Ref is if its indicated in the

 with
 | the ref keyword.
 |

 What's wrong with inout?

 -----------------------
 Carlos Santander Bernal



Now I know that D needs to be almost as fast as raw assembler code, so the method I'm about to describe will not be useful in all cases for D, but it is another way of thinking about parameter passing... In another language that I use a great deal, all parameters are passed by value (semantically). In this language, there are only two effective data types - numbers and vectors. As vectors can be arbitarily large, they are actually passed by reference but on the first write to a vector parameter, the language automatically does a copy of it and changes the reference to point to the copy. It's actually a bit more sophisticated than that, but the net effect from the coder's point of view is that you can never alter a variable being passed as a parameter from within the function being called. Also, the automatic copy-on-write feature makes this 'pass by value' fairly efficient. BTW it also does automatic garbage collection for you too. For example (not quality code but just an example!): function ToUpper(sequence x) for i = 1 to length(x) do if x[i] >= 'a' and x[i] <= 'z' then x[i] = x[i] + ('A' - 'a') end if end for return x end function sequence A, B A = "abc" B = ToUpper(A) After the call to ToUpper(), 'A' will still be "abc" and 'B' will be "ABC". In fact, if you needed to update 'A' you would code 'A = ToUpper(A)'. -- Derek 25/May/04 5:18:36 PM
May 25 2004
prev sibling next sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Norbert Nemec wrote:

<snip>
 I believe that whole business of "in", "out" and "inout" arguments is
 flawed. My first expectation, when I saw these was, that that they are
 "copy-in/copy-out" arguments. The specs are not very precise when they talk
 about this question. Somehow, I have the feeling, that D tries to hide the
 complexity of reference/value arguments from the user, but, at the same
 time, obscures and cripples the concept completely.
 
 My opinion: neither the C++ nor the D way are the solution. I don't know the
 solution, but it has to be out there somewhere.

Maybe in should've meant pass by reference, making it like out/inout, leaving no modifier to mean pass by value. At least as far as structs and atomic types go, don't ask me about arrays, obects and the like.... Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
May 25 2004
prev sibling next sibling parent Regan Heath <regan netwin.co.nz> writes:
On Tue, 25 May 2004 08:44:21 +0200, Norbert Nemec <Norbert.Nemec gmx.de> 
wrote:
 Then this boils down to the good old war about "const". Walter decided to
 make "const" a storage class, not a type modifier.

I think this was a good decision. An object *is* either const or not. But lets not re-start this argument.
 This means, we have
 const objects, you can take a pointer from them, but then the compiler 
 does
 not help you in tracking that they were const.

This should be fixed. Can you point a 'pointer to non-const' (does D even have 'pointer to const') at a const object? if so, perhaps this shouldn't be allowed.
 Introducing "ref" in addition to "inout" would just hide this fact in a 
 very
 obscure way. "inout mytype arg" would be "mytype &arg" in C++, while "ref
 mytype arg" would be "const mytype &arg".

I don't like the 'ref' idea, I think in, out and inout can do what we need.
 I believe that whole business of "in", "out" and "inout" arguments is
 flawed. My first expectation, when I saw these was, that that they are
 "copy-in/copy-out" arguments. The specs are not very precise when they 
 talk
 about this question. Somehow, I have the feeling, that D tries to hide 
 the
 complexity of reference/value arguments from the user, but, at the same
 time, obscures and cripples the concept completely.

 My opinion: neither the C++ nor the D way are the solution. I don't know 
 the
 solution, but it has to be out there somewhere.

If we adopt this idea of passing by reference *all* the time, you'd have something like: in - pass by reference, any attempt to modify causes a compile time error. out - pass by reference, initialized on entry. inout - pass by reference. a const object passed as an inout or out parameter would cause a compile time error. (I realise it may not be simple to detect the above compile time errors) I don't think you need to copy-in/copy-out. If the function writer wants to modify an 'in' parameter, then it's either not an 'in' parameter, or they only want to do it for the duration of the function so... int fn(in int _a) { int a = _a; } will suffice to make a copy they can modify for the duration of the function. What am I missing? Regan.
 Kris wrote:

 One cannot use 'inout' with a const struct, since by definition it's
 read-only.

 - Kris

 "Carlos Santander B." <carlos8294 msn.com> wrote in message
 news:c8udnv$205u$1 digitaldaemon.com...
 "imr1984" <imr1984_member pathlink.com> escribió en el mensaje
 news:c8tbvq$fm$1 digitaldaemon.com
 | I think D needs a 'ref' keyword like C# has. This way large structs 
 can

 | passed by reference without nasty pointers. The way i see it, this is

 only
 | way to support this because as Stewart says if you have a function
 exported from
 | a library, and it takes a struct, the only way for the compiler to 
 know
 that the
 | exported func takes the struct by Ref is if its indicated in the

 with
 | the ref keyword.
 |

 What's wrong with inout?

 -----------------------
 Carlos Santander Bernal



-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
May 25 2004
prev sibling parent reply Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari gamma.hut.fi> writes:
In article <c8upj2$2m2j$1 digitaldaemon.com>, Norbert Nemec wrote:
 I believe that whole business of "in", "out" and "inout" arguments is
 flawed. My first expectation, when I saw these was, that that they are
 "copy-in/copy-out" arguments. The specs are not very precise when they talk

Hmm, hmm. I just got a strange revelation... since D doesn't have const, doesn't that actually mean that inout and in are practically the same thing? (If we're talking about classes that is. Yes, it means precisely that. "in" arguments can be clobbered ruthlessly.) Actually I could think differently: since const can never be anything else than documentation of the programmer's intent, it isn't actually needed. "in" and "inout" could be as well replaced with C++'s const reference and inout with reference. Except that an "in" parameter doesn't protect the programmer from accidents. It's precisely like a const T& parameter of C++, which is then const_cast<T&>:ed implicitly inside the function body. I didn't even think (or test) about the value arguments (ints, structs and the like) yet, maybe the in/inout stuff is just cleaner when you take them into account. -Antti
 about this question. Somehow, I have the feeling, that D tries to hide the
 complexity of reference/value arguments from the user, but, at the same
 time, obscures and cripples the concept completely.
 
 My opinion: neither the C++ nor the D way are the solution. I don't know the
 solution, but it has to be out there somewhere.
 
 
 
 Kris wrote:
 
 One cannot use 'inout' with a const struct, since by definition it's
 read-only.
 
 - Kris
 
 "Carlos Santander B." <carlos8294 msn.com> wrote in message
 news:c8udnv$205u$1 digitaldaemon.com...
 "imr1984" <imr1984_member pathlink.com> escribió en el mensaje
 news:c8tbvq$fm$1 digitaldaemon.com
 | I think D needs a 'ref' keyword like C# has. This way large structs can

 | passed by reference without nasty pointers. The way i see it, this is

 only
 | way to support this because as Stewart says if you have a function
 exported from
 | a library, and it takes a struct, the only way for the compiler to know
 that the
 | exported func takes the struct by Ref is if its indicated in the

 with
 | the ref keyword.
 |

 What's wrong with inout?

 -----------------------
 Carlos Santander Bernal



-- I will not be using Plan 9 in the creation of weapons of mass destruction to be used by nations other than the US.
May 27 2004
parent J Anderson <REMOVEanderson badmama.com.au> writes:
Antti Sykäri wrote:

In article <c8upj2$2m2j$1 digitaldaemon.com>, Norbert Nemec wrote:
  

I believe that whole business of "in", "out" and "inout" arguments is
flawed. My first expectation, when I saw these was, that that they are
"copy-in/copy-out" arguments. The specs are not very precise when they talk
    

Hmm, hmm. I just got a strange revelation... since D doesn't have const, doesn't that actually mean that inout and in are practically the same thing? (If we're talking about classes that is. Yes, it means precisely that. "in" arguments can be clobbered ruthlessly.)

void test(A a) { a = new A; } void test2(inout A a) { a = new A; } void main() { A a = new A; test(a); //what is a test2(a); //what is a } -- -Anderson: http://badmama.com.au/~anderson/
May 28 2004
prev sibling next sibling parent Billy Zelsnack <billy_zelsnack yahoo.com> writes:
You can't do this:

float3 vecA=float3(0,0,0);
float3 vecB=add(vecA,float3(0,0,1));


Carlos Santander B. wrote:
 "imr1984" <imr1984_member pathlink.com> escribió en el mensaje
 news:c8tbvq$fm$1 digitaldaemon.com
 | I think D needs a 'ref' keyword like C# has. This way large structs can be
 | passed by reference without nasty pointers. The way i see it, this is the
 only
 | way to support this because as Stewart says if you have a function
 exported from
 | a library, and it takes a struct, the only way for the compiler to know
 that the
 | exported func takes the struct by Ref is if its indicated in the prototype
 with
 | the ref keyword.
 |
 
 What's wrong with inout?
 
 -----------------------
 Carlos Santander Bernal
 
 

May 24 2004
prev sibling parent reply imr1984 <imr1984_member pathlink.com> writes:
inout for a readonly parameter is inaccurate and misleading. 

Or - here is an idea - Since no one actually uses the 'in' keyword, why not make
the in keyword explicitly mean pass by reference, and the function is not
allowed to write to the pointer. This would be perfect.

In article <c8udnv$205u$1 digitaldaemon.com>, Carlos Santander B. says...
"imr1984" <imr1984_member pathlink.com> escribió en el mensaje
news:c8tbvq$fm$1 digitaldaemon.com
| I think D needs a 'ref' keyword like C# has. This way large structs can be
| passed by reference without nasty pointers. The way i see it, this is the
only
| way to support this because as Stewart says if you have a function
exported from
| a library, and it takes a struct, the only way for the compiler to know
that the
| exported func takes the struct by Ref is if its indicated in the prototype
with
| the ref keyword.
|

What's wrong with inout?

-----------------------
Carlos Santander Bernal

May 25 2004
next sibling parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
imr1984 wrote:

 inout for a readonly parameter is inaccurate and misleading.
 
 Or - here is an idea - Since no one actually uses the 'in' keyword, why
 not make the in keyword explicitly mean pass by reference, and the
 function is not allowed to write to the pointer. This would be perfect.

Sounds like a good solution! I really like that! 'in' would be the same thing as 'const &' in C++. No semantic difference to the current situation (except in the case where another function changes the data behind the reference while the called function is running but that is dangerous in any case). Just a clean way to tell the compiler what the calling convention for a given function should be (Which is an information that the compiler cannot easily deduct automatically).
May 25 2004
parent imr1984 <imr1984_member pathlink.com> writes:
In article <c8vhji$tkh$1 digitaldaemon.com>, Norbert Nemec says...
imr1984 wrote:

 inout for a readonly parameter is inaccurate and misleading.
 
 Or - here is an idea - Since no one actually uses the 'in' keyword, why
 not make the in keyword explicitly mean pass by reference, and the
 function is not allowed to write to the pointer. This would be perfect.

Sounds like a good solution! I really like that! 'in' would be the same thing as 'const &' in C++. No semantic difference to the current situation (except in the case where another function changes the data behind the reference while the called function is running but that is dangerous in any case). Just a clean way to tell the compiler what the calling convention for a given function should be (Which is an information that the compiler cannot easily deduct automatically).

exactly :)
May 25 2004
prev sibling next sibling parent reply Andy Friesen <andy ikagames.com> writes:
imr1984 wrote:

 inout for a readonly parameter is inaccurate and misleading. 
 
 Or - here is an idea - Since no one actually uses the 'in' keyword, why not
make
 the in keyword explicitly mean pass by reference, and the function is not
 allowed to write to the pointer. This would be perfect.

You would need to make sure that 'in' references are only passed to methods as 'in' arguments, and so on and so forth. It's C++ const all over again. What might be better is if the ABI said that all structs are always passed by reference. In the case of 'in' parameters, the compiler would be responsible for creating a temporary copy if one is needed. (ie if it thinks the struct is written to) Are there any arguments for passing structs by value? -- andy
May 25 2004
next sibling parent imr1984 <imr1984_member pathlink.com> writes:
In article <c8vnlv$17f4$1 digitaldaemon.com>, Andy Friesen says...
imr1984 wrote:

 inout for a readonly parameter is inaccurate and misleading. 
 
 Or - here is an idea - Since no one actually uses the 'in' keyword, why not
make
 the in keyword explicitly mean pass by reference, and the function is not
 allowed to write to the pointer. This would be perfect.

You would need to make sure that 'in' references are only passed to methods as 'in' arguments, and so on and so forth. It's C++ const all over again. What might be better is if the ABI said that all structs are always passed by reference. In the case of 'in' parameters, the compiler would be responsible for creating a temporary copy if one is needed. (ie if it thinks the struct is written to) Are there any arguments for passing structs by value? -- andy

Andy that would also work very well - No I cant think of single reason why you would want to pass a struct by value. I wish the spec was more clear on what actually happens under the hood with regards to parameter passing. So I guess that kinda makes the 'in' keyword redundant?
May 25 2004
prev sibling next sibling parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Andy Friesen wrote:

 imr1984 wrote:
 Are there any arguments for passing structs by value?

It is be faster for small structs. But I guess, if you want to go for speed, you would use inlining anyway, in which case it does not really matter. It just has to be clear what the semantics are, no matter what the compiler does to achive it. Furthermore, it has to be clear how other languages are interfaced. If you want to interface a C function that takes a struct as value on the stack, you have to be able to specify that interface in D.
May 25 2004
parent reply Andy Friesen <andy ikagames.com> writes:
Norbert Nemec wrote:

 Andy Friesen wrote:
 
 
imr1984 wrote:
Are there any arguments for passing structs by value?

It is be faster for small structs. But I guess, if you want to go for speed, you would use inlining anyway, in which case it does not really matter. It just has to be clear what the semantics are, no matter what the compiler does to achive it.

Why is it faster? And how small is small?
 Furthermore, it has to be clear how other languages are interfaced. If you
 want to interface a C function that takes a struct as value on the stack,
 you have to be able to specify that interface in D.

extern(C/Windows/Pascal) mustn't do this; it defeats their entire reason to exist. I'm suggesting behaviour for extern(D) only. -- andy
May 25 2004
next sibling parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Andy Friesen wrote:

 Norbert Nemec wrote:
 
 Andy Friesen wrote:
 
 
imr1984 wrote:
Are there any arguments for passing structs by value?

It is be faster for small structs. But I guess, if you want to go for speed, you would use inlining anyway, in which case it does not really matter. It just has to be clear what the semantics are, no matter what the compiler does to achive it.

Why is it faster? And how small is small?

Good question. If the struct is no bigger than one pointer, it is clear that it is faster since you simply save one step of dereferencing. If it is slightly bigger, dereferencing may still be more expensive than copying. Hard to tll.
 Furthermore, it has to be clear how other languages are interfaced. If
 you want to interface a C function that takes a struct as value on the
 stack, you have to be able to specify that interface in D.

extern(C/Windows/Pascal) mustn't do this; it defeats their entire reason to exist. I'm suggesting behaviour for extern(D) only.

Maybe extern(C/Windows/Pascal/...) should not use the in/inout/out modifiers at all but offer a completely separate set of modifiers fit for each case?
May 25 2004
next sibling parent Billy Zelsnack <billy_zelsnack yahoo.com> writes:
 Maybe extern(C/Windows/Pascal/...) should not use the in/inout/out modifiers
 at all but offer a completely separate set of modifiers fit for each case?

While you are at it. Allow the the extern(C/Windows/Pascal) functions have 'const' in the prototype. I end up having to do this a lot: extern(C) { void lookyLooky(/*const*/ Something* something); } In one of the C libraries I use I could just grab all of the functions intact without any changes if I didn't have to comment out all the 'const'.
May 25 2004
prev sibling parent Andy Friesen <andy ikagames.com> writes:
Norbert Nemec wrote:
 Andy Friesen wrote:
Why is it faster?  And how small is small?

Good question. If the struct is no bigger than one pointer, it is clear that it is faster since you simply save one step of dereferencing. If it is slightly bigger, dereferencing may still be more expensive than copying. Hard to tll.

A function using such a struct would be able to create a private copy if it was determined that doing so would be faster, right?
 Maybe extern(C/Windows/Pascal/...) should not use the in/inout/out modifiers
 at all but offer a completely separate set of modifiers fit for each case?

Everything except 'in' should be illegal, I think. Those conventions are already well established standards; D shouldn't mess with them. -- andy
May 25 2004
prev sibling parent reply Kevin Bealer <Kevin_member pathlink.com> writes:
In article <c8vrut$1e87$1 digitaldaemon.com>, Andy Friesen says...
Norbert Nemec wrote:

 Andy Friesen wrote:
 
 
imr1984 wrote:
Are there any arguments for passing structs by value?

It is be faster for small structs. But I guess, if you want to go for speed, you would use inlining anyway, in which case it does not really matter. It just has to be clear what the semantics are, no matter what the compiler does to achive it.

Why is it faster? And how small is small?

Depends on reference and pointer semantics. It is faster to copy small structs, because you can cache all or parts of them in registers. Consider this common swap idiom: struct foo { int a; int b; } // foo x : passed into function if (x.a > x.b) { int c = x.a; x.a = x.b; x.b = c; } If structs are pass-by-value, this needs to load x.a and x.b, write x.b to x.a, write x.a to x.b. I assume enough optimization that c can be eliminated. Thus there are four memory operations if the loop is true, two if not. If pass by reference, and "aliasing" assumptions are C89 style, then there are at least 6 memory operations, because the structs may have changed between statements. This is (one reason) why some C and C++ code will pass a struct by pointer, then copy pieces into local variables. Local variables can be "registerized" but structs can only be registerized if the current thread can be assumed to be the only user of the struct. Hopefully, D will use semantics that default to higher optimization and less aliasing, (In contradiction of a previous suggestion of mine ;). Kevin
 Furthermore, it has to be clear how other languages are interfaced. If you
 want to interface a C function that takes a struct as value on the stack,
 you have to be able to specify that interface in D.

extern(C/Windows/Pascal) mustn't do this; it defeats their entire reason to exist. I'm suggesting behaviour for extern(D) only. -- andy

May 26 2004
parent Norbert Nemec <Norbert.Nemec gmx.de> writes:
Kevin Bealer wrote:

 Hopefully, D will use semantics that default to higher optimization and
 less aliasing,  (In contradiction of a previous suggestion of mine ;).

I don't hope for too much in that respect. Aliasing is a fundamental problem in a language as soon as you have references. In Fortran77, it was trivial to avoid aliasing by simply stating that function arguments may not be aliased. This is, because function arguments were the only source of aliased symbols. Outside of a function, two different symbols always stand for two different objects in memory. Only in functions call, new names for symbols are introduced, so it is easy to prohibit this and have the problem solved completely. In languages that have pointers, aliasing happens everywhere. Prohibiting aliased function arguments only captures the tip of the iceberg. A function might use pointers from all kinds of sources, nested data-structures or whatever.
May 26 2004
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 25 May 2004 08:14:17 -0700, Andy Friesen wrote:

[snip]
 
 What might be better is if the ABI said that all structs are always 
 passed by reference.  In the case of 'in' parameters, the compiler would 
 be responsible for creating a temporary copy if one is needed. (ie if it 
 thinks the struct is written to)
 
 Are there any arguments for passing structs by value?
 

There are a couple of Windows API calls that pass a POINT struct by value. -- Derek 26/May/04 9:40:42 AM
May 25 2004
parent Andy Friesen <andy ikagames.com> writes:
Derek Parnell wrote:
 On Tue, 25 May 2004 08:14:17 -0700, Andy Friesen wrote:
 
 [snip]
 
What might be better is if the ABI said that all structs are always 
passed by reference.  In the case of 'in' parameters, the compiler would 
be responsible for creating a temporary copy if one is needed. (ie if it 
thinks the struct is written to)

Are there any arguments for passing structs by value?

There are a couple of Windows API calls that pass a POINT struct by value.

Okay. That more or less solidifies the case for extern C, Pascal, and Windows all behaving exactly as they do now. Should extern (D) preserve this behaviour for consistency's sake, or is this an opportunity for D to do the Right Thing even in the face of naive code? (indeed, make the naive approach the best one) -- andy
May 25 2004
prev sibling parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Andy Friesen wrote:

 imr1984 wrote:
 
 inout for a readonly parameter is inaccurate and misleading.
 
 Or - here is an idea - Since no one actually uses the 'in' keyword, why
 not make the in keyword explicitly mean pass by reference, and the
 function is not allowed to write to the pointer. This would be perfect.

You would need to make sure that 'in' references are only passed to methods as 'in' arguments, and so on and so forth.

True, but every function argument would be readonly by default! Either it has no argument modifier, meaning call-by-value, or it is 'in', meaning call by read-only-reference.
 It's C++ const all over again.

No! The problem in C++ was, that "const" had to be explicitly specified. So if you forgot to say it in some function, you had problems using that function legitimately. In D, you will have to explicitly state 'inout', if you want to have a read-write reference.
 What might be better is if the ABI said that all structs are always
 passed by reference.  In the case of 'in' parameters, the compiler would
 be responsible for creating a temporary copy if one is needed. (ie if it
 thinks the struct is written to)

Why not prohibit writing to function arguments alltogether (unless they are inout/out)? It is that strange C feature to make every argument automatically a local variable. I always found it bad style to use this. If you need a local variable, why not just declare one?
May 26 2004
parent reply Andy Friesen <andy ikagames.com> writes:
Norbert Nemec wrote:

 The problem in C++ was, that "const" had to be explicitly specified. So
 if you forgot to say it in some function, you had problems using that
 function legitimately. In D, you will have to explicitly state 'inout', if
 you want to have a read-write reference.

C++ const means const methods, const references, and all the headaches that they entail. The theory seems sound enough, but the compiler can't use const to optimize anything and I can't recall any instances offhand where const saved the day. I can, however, recall a whole lot of compiler errors caused by forgetting to const this or that.
What might be better is if the ABI said that all structs are always
passed by reference.  In the case of 'in' parameters, the compiler would
be responsible for creating a temporary copy if one is needed. (ie if it
thinks the struct is written to)

Why not prohibit writing to function arguments alltogether (unless they are inout/out)? It is that strange C feature to make every argument automatically a local variable. I always found it bad style to use this. If you need a local variable, why not just declare one?

Most languages I have used allow this. Why not? -- andy
May 26 2004
next sibling parent Norbert Nemec <Norbert.Nemec gmx.de> writes:
Andy Friesen wrote:

 Norbert Nemec wrote:
 
 The problem in C++ was, that "const" had to be explicitly specified. So
 if you forgot to say it in some function, you had problems using that
 function legitimately. In D, you will have to explicitly state 'inout',
 if you want to have a read-write reference.

C++ const means const methods, const references, and all the headaches that they entail. The theory seems sound enough, but the compiler can't use const to optimize anything and I can't recall any instances offhand where const saved the day. I can, however, recall a whole lot of compiler errors caused by forgetting to const this or that.

The problem in C++ is that you can have references/pointers to const. If you disallow taking the address of a const variable, the problem of const references disappears. Objects can never be const, since they are always handled as reference and you cannot have literal objects. This solves the demand for const methods. Leaves us only with const for call-by-reference arguments: this could be solved by making arguments read-only generally. If "in" would declare an argument as call-by-reference argument, this would mean you can only use it in places where a const would be allowed as well. If you use a literal as "in" argument, the compiler will have to place it in the constant data segment to be able to create a reference to it, but there is no chance anyone might ever try to write to that memory.
 Why not prohibit writing to function arguments alltogether (unless they
 are inout/out)?
 
 It is that strange C feature to make every argument automatically a local
 variable. I always found it bad style to use this. If you need a local
 variable, why not just declare one?

Most languages I have used allow this. Why not?

Because it collides with call-by-reference. For "inout/out", there is no problem, since assigning to the referenced data actually means changing that data outside of the function. For "in" parameters, on the other hand, the compiler will have to make a copy of that data, which, in a way, defies the purpose of call-by-reference. Most old programming languages allow it, since it may save one copy-operation. Today, with optimizing compilers, this does not really matter any more, so I can only call it bad programming style.
May 26 2004
prev sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <c91jku$11uv$1 digitaldaemon.com>, Andy Friesen says...
C++ const means const methods, const references, and all the headaches 
that they entail.  The theory seems sound enough, but the compiler can't 
use const to optimize anything and I can't recall any instances offhand 
where const saved the day.

Ooh, I can think of squillions of such examples. And at least one example when one of my time "worked around" my const declaration with a pointer trick, and held the project up for about two weeks while the whole team attempted to figure out how and why the heap was getting corrupted! Our app was multithreaded - that's when these things really matter.
I can, however, recall a whole lot of 
compiler errors caused by forgetting to const this or that.

That's what happens when you call functions written by other people who DIDN'T use const. I've always thought that C++ would be a much better language if it everything was const by default, and you needed a keyword, nonconst, say, to specify otherwise. That way, if you wrote a function like:
       char * strcpy(char * dst, char * src);

it would fail to compile until you changed it to:
       char * strcpy(nonconst char * dst, char * src);

(although the error would refer to the line that attempted to modify *dst, not the declaration). As things stand, forgetting const is not a compile error. Instead, it becomes impossible to use const unless you go the whole hog and change every single function you call to use the C++ const convention. In the case of D, I would dearly love to be able to declare a function like:
       void myFunction( in MyObject myObject )

****and have the compiler flag an error**** if the referenced object is modified. I cannot stress how greatly this would assist in bug catching. Right now the only way to do anything even remotely similar to this is:
       void myFunction( in MyObject myObject )
       in
       {
           myObject_backup = new MyObject(myObject);
       }
       out
       {
           assert(myObject == myObject_backup);
       }
       body
       {
           debug MyObject myObject_backup;
       }

Sheesh! After all, putting const (or in, or nonconst, or whatever) into a function declaration is simply that - a contract which the function must fulfil. If it fails to fulfil that contract, it's a bug. With all of D's emphasis on contracts, it baffles me why D doesn't implement this most useful one. Arcane Jill
May 26 2004
parent reply "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
+1, AJ

Though it might seem draconian to some, defaulting arguments to read-only
access would indeed avoid a ream of oft hard-to-find bugs. Would likely
offer up some optimization opportunities also

- Kris.

"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:c920je$1jqr$1 digitaldaemon.com...
 In article <c91jku$11uv$1 digitaldaemon.com>, Andy Friesen says...
C++ const means const methods, const references, and all the headaches
that they entail.  The theory seems sound enough, but the compiler can't
use const to optimize anything and I can't recall any instances offhand
where const saved the day.

Ooh, I can think of squillions of such examples. And at least one example

 one of my time "worked around" my const declaration with a pointer trick,

 held the project up for about two weeks while the whole team attempted to

 out how and why the heap was getting corrupted! Our app was

 that's when these things really matter.

I can, however, recall a whole lot of
compiler errors caused by forgetting to const this or that.

That's what happens when you call functions written by other people who

 use const.

 I've always thought that C++ would be a much better language if it

 was const by default, and you needed a keyword, nonconst, say, to specify
 otherwise. That way, if you wrote a function like:

       char * strcpy(char * dst, char * src);

it would fail to compile until you changed it to:
       char * strcpy(nonconst char * dst, char * src);

(although the error would refer to the line that attempted to modify *dst,

 the declaration). As things stand, forgetting const is not a compile

 Instead, it becomes impossible to use const unless you go the whole hog

 change every single function you call to use the C++ const convention.

 In the case of D, I would dearly love to be able to declare a function

       void myFunction( in MyObject myObject )

****and have the compiler flag an error**** if the referenced object is modified. I cannot stress how greatly this would assist in bug catching. Right now the only way to do anything even remotely similar to this is:
       void myFunction( in MyObject myObject )
       in
       {
           myObject_backup = new MyObject(myObject);
       }
       out
       {
           assert(myObject == myObject_backup);
       }
       body
       {
           debug MyObject myObject_backup;
       }

Sheesh! After all, putting const (or in, or nonconst, or whatever) into a function declaration is simply that - a contract which the function must fulfil. If

 fails to fulfil that contract, it's a bug.

 With all of D's emphasis on contracts, it baffles me why D doesn't

 this most useful one.

 Arcane Jill

May 26 2004
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 26 May 2004 08:02:24 -0700, Kris wrote:

 +1, AJ
 
 Though it might seem draconian to some, defaulting arguments to read-only
 access would indeed avoid a ream of oft hard-to-find bugs. Would likely
 offer up some optimization opportunities also
 
 - Kris.
 

Oh is that what all this boils down to? In that case I support the idea as well. Having worked with a language where it is impossible to change the value of function arguments, I at first thought this was a draconian 'feature'. But over the years now, I've come around to believing it has saved me from *so many* bugs AND it makes programming easier knowing that the arguments you pass to some function are never altered by that function. No side-effects! Wonderful! All parameters are only modified through explict assignments by the CALLING code and not the CALLED code. If D is not going to do automatic copy-on-write (and I don't think it should), then having the default of read-only arguments AND being allowed to explictly nominate which arguments can be modified by a function, seems to be a good idea. One question that remains is at what point do we nominate the modifiable arguments - the caller or the called? In other words ... If the caller does it (my preference so far)... A = FuncA( inout B, C, D) If the called does it ... int FuncA( inout int X, int Y, int Z) { . . . } I suppose it is not a compiler or a runtime error if the function attempts to modify read-only arguments because it could be said that its just using them as local variables. But maybe this needs more discussion and thought. -- Derek 27/May/04 10:17:35 AM
May 26 2004
next sibling parent reply Regan Heath <regan netwin.co.nz> writes:
On Thu, 27 May 2004 10:30:39 +1000, Derek Parnell <derek psych.ward> wrote:
 On Wed, 26 May 2004 08:02:24 -0700, Kris wrote:

 +1, AJ

 Though it might seem draconian to some, defaulting arguments to 
 read-only
 access would indeed avoid a ream of oft hard-to-find bugs. Would likely
 offer up some optimization opportunities also

 - Kris.

Oh is that what all this boils down to? In that case I support the idea as well. Having worked with a language where it is impossible to change the value of function arguments, I at first thought this was a draconian 'feature'. But over the years now, I've come around to believing it has saved me from *so many* bugs AND it makes programming easier knowing that the arguments you pass to some function are never altered by that function. No side-effects! Wonderful! All parameters are only modified through explict assignments by the CALLING code and not the CALLED code. If D is not going to do automatic copy-on-write (and I don't think it should), then having the default of read-only arguments AND being allowed to explictly nominate which arguments can be modified by a function, seems to be a good idea. One question that remains is at what point do we nominate the modifiable arguments - the caller or the called? In other words ... If the caller does it (my preference so far)... A = FuncA( inout B, C, D) If the called does it ... int FuncA( inout int X, int Y, int Z) { . . . }

It's going to have to be the latter I think, then it can be checked at compile time (in some/most/all? cases) Also the function writer knows what access the function needs to it's parameters, not the caller.
 I suppose it is not a compiler or a runtime error if the function 
 attempts
 to modify read-only arguments because it could be said that its just 
 using
 them as local variables. But maybe this needs more discussion and 
 thought.

I think it should be an error. If you want to modify them, then either: - they're incorrectly labelled read-only - you only want to modify them for the scope of the function, in which case what is wrong with: struct foo { int a; } int foobar(in foo a) { foo b = a; //modify/use b; } Regan. -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
May 26 2004
parent Derek Parnell <derek psych.ward> writes:
On Thu, 27 May 2004 12:59:10 +1200, Regan Heath wrote:

 On Thu, 27 May 2004 10:30:39 +1000, Derek Parnell <derek psych.ward> wrote:
 On Wed, 26 May 2004 08:02:24 -0700, Kris wrote:

 +1, AJ

 Though it might seem draconian to some, defaulting arguments to 
 read-only
 access would indeed avoid a ream of oft hard-to-find bugs. Would likely
 offer up some optimization opportunities also

 - Kris.

Oh is that what all this boils down to? In that case I support the idea as well. Having worked with a language where it is impossible to change the value of function arguments, I at first thought this was a draconian 'feature'. But over the years now, I've come around to believing it has saved me from *so many* bugs AND it makes programming easier knowing that the arguments you pass to some function are never altered by that function. No side-effects! Wonderful! All parameters are only modified through explict assignments by the CALLING code and not the CALLED code. If D is not going to do automatic copy-on-write (and I don't think it should), then having the default of read-only arguments AND being allowed to explictly nominate which arguments can be modified by a function, seems to be a good idea. One question that remains is at what point do we nominate the modifiable arguments - the caller or the called? In other words ... If the caller does it (my preference so far)... A = FuncA( inout B, C, D) If the called does it ... int FuncA( inout int X, int Y, int Z) { . . . }

It's going to have to be the latter I think, then it can be checked at compile time (in some/most/all? cases) Also the function writer knows what access the function needs to it's parameters, not the caller.
 I suppose it is not a compiler or a runtime error if the function 
 attempts
 to modify read-only arguments because it could be said that its just 
 using
 them as local variables. But maybe this needs more discussion and 
 thought.

I think it should be an error. If you want to modify them, then either: - they're incorrectly labelled read-only - you only want to modify them for the scope of the function, in which case what is wrong with: struct foo { int a; } int foobar(in foo a) { foo b = a; //modify/use b; }

Yeah, that makes sense. Also if the caller is worried about a function changing the parameters, the caller can pass a copy. int Xcopy = X; foobar( Xcopy ); -- Derek 27/May/04 11:58:28 AM
May 26 2004
prev sibling parent Norbert Nemec <Norbert.Nemec gmx.de> writes:
Derek Parnell wrote:

 On Wed, 26 May 2004 08:02:24 -0700, Kris wrote:
 
 +1, AJ
 
 Though it might seem draconian to some, defaulting arguments to read-only
 access would indeed avoid a ream of oft hard-to-find bugs. Would likely
 offer up some optimization opportunities also
 
 - Kris.
 

Oh is that what all this boils down to? In that case I support the idea as well. Having worked with a language where it is impossible to change the value of function arguments, I at first thought this was a draconian 'feature'. But over the years now, I've come around to believing it has saved me from *so many* bugs AND it makes programming easier knowing that the arguments you pass to some function are never altered by that function. No side-effects! Wonderful! All parameters are only modified through explict assignments by the CALLING code and not the CALLED code.

Abolishing side-effects completely would be a long step from the C philosophy and a rather radical change in D. I don't think, we can get all that far. Of course, other languages (especially functional languages) do it and it saves them a number of problems. But C/C++/D are not functional. All I thought about was making 'in' parameters readonly within the function, instead of turning them into local variables that can be changed, but whose value is lost. Alternatively, you could have the compiler to automatically insert a copying instruction on read-only call-by-reference arguments.
 
 If D is not going to do automatic copy-on-write (and I don't think it
 should), then having the default of read-only arguments AND being allowed
 to explictly nominate which arguments can be modified by a function, seems
 to be a good idea. One question that remains is at what point do we
 nominate the modifiable arguments - the caller or the called? In other
 words ...
 
 If the caller does it (my preference so far)...
    A = FuncA( inout B, C, D)
 
 If the called does it ...
    int FuncA( inout int X, int Y, int Z)
    { . . . }

The second one if needed in any case (and is in the specs already) since 'inout' is a matter of the interface. Adding the first one would only be redundancy which is not exactly D style.
May 26 2004
prev sibling parent Billy Zelsnack <billy_zelsnack yahoo.com> writes:
imr1984 wrote:
 inout for a readonly parameter is inaccurate and misleading. 
 
 Or - here is an idea - Since no one actually uses the 'in' keyword, why not
make
 the in keyword explicitly mean pass by reference, and the function is not
 allowed to write to the pointer. This would be perfect.

haha. That's what I thought 'in' did before I figured out it didn't really mean anything. It makes sense though. 'out' means out only. 'inout' means both. 'in' would make sense to mean in only.
May 25 2004