www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing arguments into functions - in, out, inout, const, and contracts

reply Jason House <jason.james.house gmail.com> writes:
I believe that everything (except maybe fundamental types such as int) 
are passed by reference.  I'd expect "in" parameters to be considered 
const, but I know that member functions can't be declared const.

It seems to me that in/out/inout has no effect on how the language 
operates.  I'm wondering how those affect the language.  Does "in" 
impose a contract that the ending value must equal the starting value? 
I also haven't thought of any good way to differentiate out from inout 
from the compiler's standpoint (obviously, it makes sense to users).
Feb 10 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jason House wrote:
 I believe that everything (except maybe fundamental types such as int) 
 are passed by reference.  I'd expect "in" parameters to be considered 
 const, but I know that member functions can't be declared const.
 
 It seems to me that in/out/inout has no effect on how the language 
 operates.  I'm wondering how those affect the language.  Does "in" 
 impose a contract that the ending value must equal the starting value? I 
 also haven't thought of any good way to differentiate out from inout 
 from the compiler's standpoint (obviously, it makes sense to users).

All structs are passed by value unless you use 'inout'. Also you can't change the identity of an object reference unless you pass it inout. As in: void make_me_new_again(inout Object obj) { obj = new Object; } . . . make_me_new_again(myObj); If that wasn't inout the caller would still be holding onto the same object that was passed in. inout makes plenty of difference. Don't know about out. It's pretty much the same as inout, with (perhaps?) some compile-time checks to make sure you don't try to read the value in the function. Seems pretty useless to me. Much more useful would be inbyref or some kind of const reference parameter. But that's supposedly in the works. 'In' is just the default. If you don't specify anything it's 'in'. But it doesn't enforce or check any pre or post conditions. --bb
Feb 10 2007
parent Mike Parker <aldacron71 yahoo.com> writes:
Bill Baxter wrote:
 Jason House wrote:

 
 Don't know about out.  It's pretty much the same as inout, with 
 (perhaps?) some compile-time checks to make sure you don't try to read 
 the value in the function.  Seems pretty useless to me.  Much more 
 useful would be inbyref or some kind of const reference parameter.  But 
 that's supposedly in the works.

out sets the value of the parameter to its initializer. Otherwise it's identical to inout.
Feb 11 2007
prev sibling next sibling parent Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Jason House wrote:
 I believe that everything (except maybe fundamental types such as int) 
 are passed by reference.  I'd expect "in" parameters to be considered 
 const, but I know that member functions can't be declared const.
 

No. This is precisely backwards. Everything is passed by value, except for certain high-level types like classes and arrays. Even then, in/out/inout still controls whether the function can reassign the reference.
 It seems to me that in/out/inout has no effect on how the language 
 operates.  I'm wondering how those affect the language.  Does "in" 
 impose a contract that the ending value must equal the starting value? I 
 also haven't thought of any good way to differentiate out from inout 
 from the compiler's standpoint (obviously, it makes sense to users).

Take the following code: import std.stdio : writefln; class Foo { int i; this(int i) { this.i = i; } } void func1(Foo f) { f = new Foo(100); } void func2(Foo f) { f.i = 30; } void func3(inout Foo f) { f = new Foo(200); } void func4(int i) { i = 20; } void func5(inout int i) { i = 25; } void main() { int i, j; Foo a, b, c; a = new Foo(1); b = new Foo(2); c = new Foo(3); func1(a); writefln(a.i); // Prints 1. The reference was passed 'in', so the // function does not change it. func2(b); writefln(b.i); // Prints 30. The object was passed by reference, // and the function mutated it. func3(c); writefln(c.i); // Prints 200. The reference was passed 'inout', // so the function does change it. func4(i); writefln(i); // Prints 0. The int was passed 'in'. func5(j); writefln(j); // Prints 25. The int was passed 'inout'. } -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Feb 10 2007
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
On Sun, 11 Feb 2007 01:09:33 -0500, Jason House wrote:

 I believe that everything (except maybe fundamental types such as int) 
 are passed by reference.  I'd expect "in" parameters to be considered 
 const, but I know that member functions can't be declared const.
 
 It seems to me that in/out/inout has no effect on how the language 
 operates.  I'm wondering how those affect the language.  Does "in" 
 impose a contract that the ending value must equal the starting value? 
 I also haven't thought of any good way to differentiate out from inout 
 from the compiler's standpoint (obviously, it makes sense to users).

Everyone describes the in/inout/out attributes in a different manner, so I may as well be a part of that movement too <G> ** 'in' ** causes the parameter to be passed by value. This means that whatever the called function does to the passed parameter, the original value prior to being called is not modified. In effect, the caller passes a copy of the parameter's value to the called program. But the usual misunderstanding is 'what exactly is the parameter'? For scalar types (char, int, float, etc...) this is simply a copy of the arguments value. For structs, it is a copy of the whole struct. For fixed-length arrays, it is a copy of the entire array. For variable-length arrays and for objects, it is the copy of the reference that is given to the called program and not the data that the reference points to. This means that the called program can mess about with the reference all it likes but the original reference is unchanged. Thus if a function is passed a char[] parameter, and the function changes the length, the array's length doesn't actually get changed. This also means that the called function has unrestricted access to the data being referred to, so that even if a char[] is passed as 'in', the function is still free to modified the characters in that array - just not its RAM pointer or its length. char[] a = "abc".dup; void foo(in char[] x) { x[1] = 'B'; // This will replace the second character. x ~= 'd'; // This doesn't actually change the length. } std.stdio.writefln("%s", a); // outputs "aBc"; ** 'inout' ** causes the parameter to be passed by reference. This means that the called function actually gets the address of the argument rather than its value. Having the address, means that it can get its current value and change it such that the change is propagated back to the caller. This has implications for variable-length arrays and objects. In these cases, the called function receives the address of the reference. And with that the function can modify the reference. For example if the function receives an inout char[], it can change the length of the string and/or change its location in RAM. char[] a = "abc".dup; void foo(inout char[] x) { x[1] = 'B'; // This will replace the second character. x ~= 'd'; // Change its length, and if this means that the // allocated RAM needs to be expanded, the function // also allocates new RAM can copies the old data // to it and invalidates the old RAM for potential // GC cleanup. } std.stdio.writefln("%s", a); // outputs "aBcd"; In the above example had just been "void foo(in char[] x)" then the string would have been effected because "foo" would have been playing around with a copy of the reference and not the reference itself. ** 'out' ** identical to inout except that the parameter being passed is initialized to the default value(s) prior to the function getting control. This is only used by functions that return data without considering the data's previous value. int a = 4; void foo(out int x) { // Because the parameter is 'out', the value passed will // always be zero because that is the initial value for an // int datatype. if (x > 1) x = 10; // Never executed because 'out' always inits the parm. else x = 1; } foo(a); // Disregard the current value in 'a' as foo // will either initialize it or set it to something. std.stdio.writefln("%s", a); // outputs 1; A special note with respect to reference data types (variable-length arrays and objects): The D programming language does not yet have a parameter passing mechanism that ensures that referenced data cannot be changed by the called function. This is because D either passes a copy of the reference or the address of the reference. In either case, the called function has access to the data being referenced. This means that regardless of whether or not you use use in/inout/out on a variable-length array or object parameter, the called function can still modified the array/object's data. The calling function cannot prevent that or otherwise guarrentee that the called function will behave itself. If you positively must ensure that passed data is preserved, only pass a copy. char[] a; // Some string data. a = bar(); // fill the string with something. foo( a.dup ); // Pass a copy to prevent foo from messing with it. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Feb 11 2007
prev sibling parent reply Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
Jason House wrote:
 I believe that everything (except maybe fundamental types such as int)
 are passed by reference.  I'd expect "in" parameters to be considered
 const, but I know that member functions can't be declared const.
 
 It seems to me that in/out/inout has no effect on how the language
 operates.  I'm wondering how those affect the language.  Does "in"
 impose a contract that the ending value must equal the starting value? I
 also haven't thought of any good way to differentiate out from inout
 from the compiler's standpoint (obviously, it makes sense to users).

Have a look at the doc: section "Function Parameters" at http://www.digitalmars.com/d/function.html After getting the code example improved via Issue 511, I feel it explains things enough. Feel free to go file another Issue at http://d.puremagic.com/issues/index.cgi if you believe it's still too unclear. -- Remove ".doesnotlike.spam" from the mail address.
Feb 11 2007
parent Jason House <jason.james.house gmail.com> writes:
Deewiant wrote:
 Jason House wrote:
 I believe that everything (except maybe fundamental types such as int)
 are passed by reference.  I'd expect "in" parameters to be considered
 const, but I know that member functions can't be declared const.

 It seems to me that in/out/inout has no effect on how the language
 operates.  I'm wondering how those affect the language.  Does "in"
 impose a contract that the ending value must equal the starting value? I
 also haven't thought of any good way to differentiate out from inout
 from the compiler's standpoint (obviously, it makes sense to users).

Have a look at the doc: section "Function Parameters" at http://www.digitalmars.com/d/function.html After getting the code example improved via Issue 511, I feel it explains things enough. Feel free to go file another Issue at http://d.puremagic.com/issues/index.cgi if you believe it's still too unclear.

It's now issue 955. I found the responses to my e-mail far more helpful than the online docs.
Feb 12 2007