www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Func Param Confusion - in/out/inout/ref/const/immutable

reply "Zane" <zane.sims gmail.com> writes:
When is it appropriate to use in, out, inout, ref, immutable, and 
const in function parameters? I read the documentation and 
understand the basics behind them, but I'm a little confused, for 
example, why someone would want to use 'out' instead of 'ref', 
why 'in' instead of 'const', or why 'immutable' instead of 
'const'? If 'inout' is used as a wildcard, allowing for any of 
several storage classes, why is it needed at all (wouldn't 'ref' 
work?). The more I think I get it, the more I end up getting 
confused. Am I thinking about this too hard? FYI: I come from 
primarily a C/Java/PHP background, so these concepts are 
relatively new to me - it feels excessive, though I am willing to 
learn.
Feb 22 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/22/2013 11:19 AM, Zane wrote:
 When is it appropriate to use in, out, inout, ref, immutable, and const
 in function parameters? I read the documentation and understand the
 basics behind them, but I'm a little confused, for example,
You are not alone. :)
 why someone would want to use 'out' instead of 'ref'
There is an idiom in C where a function first sets its "out parameter" to null (or another initial value) and then does some more work to fill that to actual result of the function: int make_something(Something ** p) { int err = 0; assert(p); *p = NULL; // first, initialize // fill in p later on return err; } To me, 'out' of D does that initialization automatically.
 why 'in' instead of 'const',
'in' is nothing but 'const scope'. As scope is not implemented yet, in and const feel the same.
 or why 'immutable' instead of 'const'?
There is a very big semantic difference between those two: const can take mutable, const, and immutable. In that sense, it is "welcoming." immutable is demanding: It wants immutable perhaps because the immutable data will be stored for later use. An alternative for the function is to take const and then to make an immutable copy but that is sometimes wasteful. If the function communicates its need to the caller, the caller hands over the immutable data, if the data is immutable to begin with. No copy needed in that case. Of course the caller may need to make an immutable copy from mutable data, but again, that copy is not wasted. Further, the caller may call assumeUnique to convert mutable data to immutable.
 If 'inout' is used as a wildcard,
 allowing for any of several storage classes, why is it needed at all
 (wouldn't 'ref' work?).
inout can transfer that information to the return type: inout(Something) foo(inout(Something) parameter) { // ... }
 The more I think I get it, the more I end up
 getting confused. Am I thinking about this too hard? FYI: I come from
 primarily a C/Java/PHP background, so these concepts are relatively new
 to me - it feels excessive, though I am willing to learn.
I have tried to capture most of these concepts in the following chapters: http://ddili.org/ders/d.en/const_and_immutable.html http://ddili.org/ders/d.en/function_parameters.html http://ddili.org/ders/d.en/const_member_functions.html Ali -- D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html
Feb 22 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 why someone would want to use 'out' instead of 'ref'
There is an idiom in C where a function first sets its "out parameter" to null (or another initial value) and then does some more work to fill that to actual result of the function: int make_something(Something ** p) { int err = 0; assert(p); *p = NULL; // first, initialize // fill in p later on return err; } To me, 'out' of D does that initialization automatically.
Another advantage of "out" is that it clearly documents that argument as another result of the function. In practice in not-performance critical functions I sometimes prefer to return multiple values in a tuple, despite D doesn't yet have a tuple unpack syntax. One disadvantage of "out" arguments in D is that D (unlike Ada, I think) doesn't forbid you to set a out argument to some value before the function call. Such assignment is always useless, and sometimes it risks being a programmer mistake. A tuple result doesn't have such bug risk. Bye, bearophile
Feb 22 2013
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Feb 22, 2013 at 08:19:49PM +0100, Zane wrote:
 When is it appropriate to use in, out, inout, ref, immutable, and
 const in function parameters?
Don't use 'in', because it doesn't mean what it seems to mean, and it's not correctly implemented at the moment.
 I read the documentation and understand the basics behind them, but
 I'm a little confused, for example, why someone would want to use
 'out' instead of 'ref', why 'in' instead of 'const', or why
 'immutable' instead of 'const'?
The difference between 'ref' and 'out' is that 'out' will default-initialize the parameter, so the function will not see whatever original value is in the variable that you pass in, whereas 'ref' is for passing in an initial value and (possibly) receiving a new value afterwards. 'immutable' is for when you want to be 100% sure that whatever value it is cannot be changed by a third party. With 'const', it just means the function can't modify the value, but somebody else may have a writable alias to the same data. You want to use 'immutable' when your function needs to assume that no external agents can change the data (e.g., if the function puts the data in some kind of persistent data structure that depends on the value not being changed from outside unexpectedly).
 If 'inout' is used as a wildcard, allowing for any of several storage
 classes, why is it needed at all (wouldn't 'ref' work?).
What 'inout' means is that the parameter is either mutable or const, and that whatever this qualifier is, the return value will acquire the same qualifier. For example: inout(int) func(inout(int[]) values, int idx) { return values[idx]; } The compiler actually treats it as two different functions: int func(int[] values, int idx) and: const(int) func(const(int[]) values, int idx) This is because int and const(int) are different types, so you couldn't write the same function for it even if the function body is identical. In order to alleviate the tedium (and bug-proneness) of copy-n-pasting the function body, 'inout' was introduced, so that by writing inout(int), you can write the function once, and it can be used for both const(int[]) and int[]. Within the function body, an inout value is treated exactly like const, that is, the function is not allowed to modify it. This is to guarantee that the function doesn't do something fishy to modify the data, since otherwise it would be wrong to allow passing const(int[]) to the same function, which means it cannot be an inout function.
 The more I think I get it, the more I end up getting confused. Am I
 thinking about this too hard? FYI: I come from primarily a C/Java/PHP
 background, so these concepts are relatively new to me - it feels
 excessive, though I am willing to learn.
It may help to understand that D's const is different from C/C++'s const. D's const comes with compiler guarantees; it means *physical* const, not logical const. That is, the physical binary representation of the data is not modifiable; so something like a class that caches function results will not be allowed to be const. This diagram will be most helpful to understand how it all works: const / \ mutable immutable What this means is that you can implicitly convert mutable or immutable into const, but you cannot go the other way, and you cannot convert between mutable and immutable (with the exception of certain safe operations, like making a copy of immutable(int), which is allowed because it's a POD that actually gets copied into a new physical location, so assigning immutable(int) to int is allowed. But in general, immutable(X) cannot be assigned to X). Generally, function parameters don't need to be immutable (except for special cases); usually you'd use const because then you can pass in either mutable (i.e. unqualified) or immutable, and it will work correctly. Hope this helps. T -- He who laughs last thinks slowest.
Feb 22 2013
parent "Zane" <zane.sims gmail.com> writes:
Both replies are extremely helpful - thank you both very much!
Feb 22 2013