digitalmars.D.bugs - Out parameters and initialization
- Unknown W. Brackets (30/30) Feb 19 2006 The spec says:
- Thomas Kuehne (17/43) Feb 23 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Unknown W. Brackets (16/17) Feb 24 2006 I may have been unclear, but this is the thing I was most specifically
- Ivan Senji (17/38) Feb 24 2006 Oops, missed this thread before.
- Unknown W. Brackets (2/47) Feb 24 2006
- Ivan Senji (20/22) Feb 25 2006 In the spec? As far as I know it isn't (at least I didn't see it anywher...
- Unknown W. Brackets (12/43) Feb 25 2006 Honestly, I understand the usefulness and where you're coming from, but
- Ivan Senji (20/35) Feb 25 2006 And I honestly understand what behaviour you want. It happens that I
- Unknown W. Brackets (19/65) Feb 25 2006 I understand it is useful. Indeed, the following, if it worked, could
- Regan Heath (38/45) Feb 25 2006 Ok, so lets look at the consistency of this.
- Derek Parnell (5/8) Feb 25 2006 This makes a lot of sense to me.
- Unknown W. Brackets (16/94) Feb 25 2006 If that is the meaning, some symbol should be used to indicate that
- Regan Heath (38/104) Feb 25 2006 The symbols 'inout' and 'out' indicate an alias/reference is being made.
- Regan Heath (4/7) Feb 25 2006 Oops, here I am muddying the waters, "default initialiser" should read
- Unknown W. Brackets (11/87) Feb 25 2006 Except aliases and typedefs (exactly, as I could tell, for the reason of...
- Ivan Senji (4/17) Feb 26 2006 Maybe, but noone is stoping you from implementing thread safe access to
- Regan Heath (4/7) Feb 26 2006 You realise 'inout' aliases the parameter in the same was as 'out' does?
- Unknown W. Brackets (7/16) Feb 26 2006 I'm thinking from the "in-side". In my mind, if I leave off an out or
- Ivan Senji (10/14) Feb 26 2006 If you don't want a result the solution is easy:
- Unknown W. Brackets (16/34) Feb 26 2006 Obviously that has nothing to do with what I meant.
- Ivan Senji (12/34) Feb 26 2006 I see that now:
- Unknown W. Brackets (16/60) Feb 26 2006 Yes, but this is a topic about a bug. We are no longer really talking
- Regan Heath (50/60) Feb 26 2006 True, however you can use the same default global for every parameter of...
- Unknown W. Brackets (40/125) Feb 26 2006 Given the following example:
- Ivan Senji (17/66) Feb 26 2006 Don't see what the problem is, you as an author of foo know what you are...
- Regan Heath (4/12) Feb 26 2006 I couldn't have put it better Ivan. "[Unknown]" you have my apologies al...
- Ivan Senji (13/33) Feb 26 2006 Do we agree then that the bug is that
- Derek Parnell (40/46) Feb 26 2006 I'm writing this without reading the entire thread, so please excuse me ...
- Ivan Senji (12/67) Feb 26 2006 Correct.
The spec says: out parameters are set to the default initializer for the type of it. Which makes perfect sense, and works just fine. The trick comes in when I try some parameter initialization. This really weirded me out at first. Example: int main() { uint i = 0; test(i); return 0; } void test(out uint i = 5) { assert(i == 5); } It seems to me that I should either get an error from the compiler, or this should compile and run without any assertions failing. However, the assert on line 11 does not pass, as of DMD 0.147. Either way, I would suggest the sentence in the spec be clarified (and the grammar buffed), for example: out parameters are always set to the default initializer for their type. Using an initializer on an out parameter is an error. Or: out parameters are always set to the default initializer for their type, unless they have an explicit initializer (but regardless of the parameters initial value.) I couldn't find this reported before, but if it has been please forgive the duplicate. Hope that's helpful, -[Unknown]
Feb 19 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Unknown W. Brackets schrieb am 2006-02-20:The spec says: out parameters are set to the default initializer for the type of it. Which makes perfect sense, and works just fine. The trick comes in when I try some parameter initialization. This really weirded me out at first. Example: int main() { uint i = 0; test(i); return 0; } void test(out uint i = 5) { assert(i == 5); } It seems to me that I should either get an error from the compiler, or this should compile and run without any assertions failing. However, the assert on line 11 does not pass, as of DMD 0.147. Either way, I would suggest the sentence in the spec be clarified (and the grammar buffed), for example: out parameters are always set to the default initializer for their type. Using an initializer on an out parameter is an error. Or: out parameters are always set to the default initializer for their type, unless they have an explicit initializer (but regardless of the parameters initial value.)Where exactly are default parameters for functions documented? changelog: | Added default arguments to function parameters. Semantics are like C++. functions: | A functions parameter's default value is not inherited. C++ has - as far as I'm aware - no out keyword. Added to DStress as http://dstress.kuehne.cn/undefined/default_argument_10.d Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFD/rXF3w+/yD4P9tIRAnagAJ49GTZBvwbg4gQG3x2vweQsCJsTbwCguviK tP/CaKTY4XUpBuCgkyI0Xu8= =mkMH -----END PGP SIGNATURE-----
Feb 23 2006
I may have been unclear, but this is the thing I was most specifically referencing; that there was no defined behavior for this in the spec's wording. As for default parameters (initializers) being defined at all, that's in the declarations page: Parameter: Declarator Declarator = AssignExpression InOut Declarator InOut Declarator = AssignExpression This presumably implies it has the same semantics as DeclaratorInitializer, but there's no explicit definition. Further, it is interesting to me that AssignExpression is used instead of Initializer; this may actually mean different semantics (and not just that you cannot use array/struct literals and void here.) -[Unknown]Where exactly are default parameters for functions documented?
Feb 24 2006
Unknown W. Brackets wrote:The spec says: out parameters are set to the default initializer for the type of it. Which makes perfect sense, and works just fine. The trick comes in when I try some parameter initialization. This really weirded me out at first. Example: int main() { uint i = 0; test(i); return 0; } void test(out uint i = 5) { assert(i == 5); }Oops, missed this thread before. Actually it kind of makes sence to me that this doesn't work. But this does work, and is IMO a great feature: int globalI = 0; int main() { uint i = 0; test(); //globalI is now 5 return 0; } void test(out uint i = globalI) { i = 5; assert(i == 5); }
Feb 24 2006
Where is that in the spec? Why is that logical? -[Unknown]Unknown W. Brackets wrote:The spec says: out parameters are set to the default initializer for the type of it. Which makes perfect sense, and works just fine. The trick comes in when I try some parameter initialization. This really weirded me out at first. Example: int main() { uint i = 0; test(i); return 0; } void test(out uint i = 5) { assert(i == 5); }Oops, missed this thread before. Actually it kind of makes sence to me that this doesn't work. But this does work, and is IMO a great feature: int globalI = 0; int main() { uint i = 0; test(); //globalI is now 5 return 0; } void test(out uint i = globalI) { i = 5; assert(i == 5); }
Feb 24 2006
Unknown W. Brackets wrote:Where is that in the spec? Why is that logical?In the spec? As far as I know it isn't (at least I didn't see it anywhere). Logical because: void func(in int x = 7); means this is an input value and if I don't suply one the default value will be 7. void func(out int x = globalX); out tels us the value of x will be changed, the default value says if I don't suply an argument change by default the value of variable globalX. If you did something like: void func(out int x = 7) { x = 11; } the compiler will complain about 7 not being an l-value. It is the same reason why you can't call the above function like func(11); 11 can not be assigned to. The above effect can be/(should be able to be) achieved by typedef int int7 = 7; or something like this. I hope this is the way it is ment to work and not some crazy bug because I'm really starting to like this feature.
Feb 25 2006
Honestly, I understand the usefulness and where you're coming from, but if that's really intended it makes absolutely no logical sense to me. That would be like this working: int i = 0; int j = i; j = 5; assert(i == 5); I realize that out is a reference/pointer type thing (automatically), but if there's no * there or anything, I don't want other variables to change. It completely contradicts everything else in the language to me.... maybe it's just me, though. -[Unknown]Unknown W. Brackets wrote:Where is that in the spec? Why is that logical?In the spec? As far as I know it isn't (at least I didn't see it anywhere). Logical because: void func(in int x = 7); means this is an input value and if I don't suply one the default value will be 7. void func(out int x = globalX); out tels us the value of x will be changed, the default value says if I don't suply an argument change by default the value of variable globalX. If you did something like: void func(out int x = 7) { x = 11; } the compiler will complain about 7 not being an l-value. It is the same reason why you can't call the above function like func(11); 11 can not be assigned to. The above effect can be/(should be able to be) achieved by typedef int int7 = 7; or something like this. I hope this is the way it is ment to work and not some crazy bug because I'm really starting to like this feature.
Feb 25 2006
Unknown W. Brackets wrote:Honestly, I understand the usefulness and where you're coming from, but if that's really intended it makes absolutely no logical sense to me.And I honestly understand what behaviour you want. It happens that I accidently found this behaviour and find it usefull.That would be like this working: int i = 0; int j = i; j = 5; assert(i == 5);Well with this I don't agree. int here isn't a reference type. (And I know that you didn't really mean this as an equivalent example)I realize that out is a reference/pointer type thing (automatically), but if there's no * there or anything, I don't want other variables to change. It completely contradicts everything else in the language to me.... maybe it's just me, though.I see it like this (maybe I'm repeating my self) void func(in int a = 5) //func(), use default in value of 5 Default values are ment for cases when *no arguments* are specified: void func(out int a = 7) { a = 3; } func(); //what is the above code doing? Assigning 3 to what? To 7? That isn't possible because 7 is a constant. The idea that a function void func(out int a = 7){} when called like this: func(b); is assigning 7 to b, contradicts the meaning of default in arguments.
Feb 25 2006
I understand it is useful. Indeed, the following, if it worked, could possibly also be useful: label: // Never executed. x = 1; comefrom label; That does not make it logical or consistent. It makes it confusing and inconsistent. Utility is not at all my concern. In other words, you're essentially saying that this makes sense: var2 = 2; var1 = var2; var1 = 1; assert(var2 == 1); If it were the other way around (var2 = var1) or if either variable had anything to do with C-style references or pointers, I might agree with you. But even if they were classes, this would make no sense whatsoever. It simply is not consistent with the rest of the language. If it's going to work that way, it should do so everywhere. -[Unknown]Unknown W. Brackets wrote:Honestly, I understand the usefulness and where you're coming from, but if that's really intended it makes absolutely no logical sense to me.And I honestly understand what behaviour you want. It happens that I accidently found this behaviour and find it usefull.That would be like this working: int i = 0; int j = i; j = 5; assert(i == 5);Well with this I don't agree. int here isn't a reference type. (And I know that you didn't really mean this as an equivalent example)I realize that out is a reference/pointer type thing (automatically), but if there's no * there or anything, I don't want other variables to change. It completely contradicts everything else in the language to me.... maybe it's just me, though.I see it like this (maybe I'm repeating my self) void func(in int a = 5) //func(), use default in value of 5 Default values are ment for cases when *no arguments* are specified: void func(out int a = 7) { a = 3; } func(); //what is the above code doing? Assigning 3 to what? To 7? That isn't possible because 7 is a constant. The idea that a function void func(out int a = 7){} when called like this: func(b); is assigning 7 to b, contradicts the meaning of default in arguments.
Feb 25 2006
On Sat, 25 Feb 2006 16:21:23 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:That does not make it logical or consistent. It makes it confusing and inconsistent. Utility is not at all my concern.Ok, so lets look at the consistency of this.In other words, you're essentially saying that this makes sense: var2 = 2; var1 = var2; var1 = 1; assert(var2 == 1);No, he's saying that this makes sense: void foo(inout int var1) { var1 = 1; } int var2 = 2; foo(var2); assert(var2 == 1); Remember, 'inout' aliases the variable you pass, the parameter 'var1' is another name for the variable 'var2'. So, when you write: void foo(inout int var1 = 7) what are you saying? Lets start with what a default parameters means, in this case: void foo(int var1 = 7) {} says, if I do not get passed a variable, pass 7, in other words: foo(); is called as: foo(7); Agreed? Therefore: void foo(inout int var1 = 7) says, if I do not get passed a variable, pass 7, meaning: foo(); is called as: foo(7); Agreed? Now, as well all know you cannot pass '7' as inout because you cannot alias '7'. What I am trying to show here is that default parameters are behaving both logically and consistently, they always mean: "If I do not get passed a variable, pass X" where X is the default parameter value supplied. Further, 'inout' is behaving both logically and consistently, in all cases it aliases the parameter which is passed. The behaviour of 'in'+'default parameter' is not the same as 'inout'+'default parameter' but why should it be? IMO one is an apple and the other an orange. Regan
Feb 25 2006
On Sun, 26 Feb 2006 12:56:04 +1100, Regan Heath <regan netwin.co.nz> wrote:The behaviour of 'in'+'default parameter' is not the same as 'inout'+'default parameter' but why should it be? IMO one is an apple and the other an orange.This makes a lot of sense to me. -- Derek Parnell Melbourne, Australia
Feb 25 2006
If that is the meaning, some symbol should be used to indicate that there is a reference being made. I don't think, personally, it makes any sense to say that in is a replacement for what might be passed. It is much more like an initializer, which would never behave in that way. To me, it is unclear and unlike the rest of the language to do as you suggest. Your suggestion separates the logic of parameter defaulting from initialization completely, but they share the same syntax (as they share again with assignment.) I think this is, at best, unclear and clumsy. At worst, it is obviously inconsistent and confusing. But that is more of a philosophical debate, and that will be for Walter to answer, ultimately. My point is that there is a bug here, nonetheless. Regardless of what you are saying, why should my initial example compile? It should either work as initialization, or not compile. It should not compile and do nothing. This is also unclear and inconsistent. -[Unknown]On Sat, 25 Feb 2006 16:21:23 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:That does not make it logical or consistent. It makes it confusing and inconsistent. Utility is not at all my concern.Ok, so lets look at the consistency of this.In other words, you're essentially saying that this makes sense: var2 = 2; var1 = var2; var1 = 1; assert(var2 == 1);No, he's saying that this makes sense: void foo(inout int var1) { var1 = 1; } int var2 = 2; foo(var2); assert(var2 == 1); Remember, 'inout' aliases the variable you pass, the parameter 'var1' is another name for the variable 'var2'. So, when you write: void foo(inout int var1 = 7) what are you saying? Lets start with what a default parameters means, in this case: void foo(int var1 = 7) {} says, if I do not get passed a variable, pass 7, in other words: foo(); is called as: foo(7); Agreed? Therefore: void foo(inout int var1 = 7) says, if I do not get passed a variable, pass 7, meaning: foo(); is called as: foo(7); Agreed? Now, as well all know you cannot pass '7' as inout because you cannot alias '7'. What I am trying to show here is that default parameters are behaving both logically and consistently, they always mean: "If I do not get passed a variable, pass X" where X is the default parameter value supplied. Further, 'inout' is behaving both logically and consistently, in all cases it aliases the parameter which is passed. The behaviour of 'in'+'default parameter' is not the same as 'inout'+'default parameter' but why should it be? IMO one is an apple and the other an orange. Regan
Feb 25 2006
On Sat, 25 Feb 2006 18:58:44 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:If that is the meaning, some symbol should be used to indicate that there is a reference being made.The symbols 'inout' and 'out' indicate an alias/reference is being made.I don't think, personally, it makes any sense to say that in is a replacement for what might be passed. It is much more like an initializer, which would never behave in that way. To me, it is unclear and unlike the rest of the language to do as you suggest.I didn't mean to suggest that 'in' was a replacement for what is passed, but rather that the default initialiser is a replacement for what _isn't_ passed.Your suggestion separates the logic of parameter defaulting from initialization completely, but they share the same syntax (as they share again with assignment.) I think this is, at best, unclear and clumsy. At worst, it is obviously inconsistent and confusing.I think you make a valid point here. default parameters, and assignment (which initialization is essentially) share the same syntax, they both use '='. It does suggest that a default parameter is an initializer, when in fact, I believe it's not that at all. That same syntax, '=', is likely the cause of this thread :)But that is more of a philosophical debate, and that will be for Walter to answer, ultimately. My point is that there is a bug here, nonetheless.I agree, my idea at the solution is below.Regardless of what you are saying, why should my initial example compile? should not compile, it shouldIt should either work as initialization, or not compile. It should not compile and do nothing. This is also unclear and inconsistent.Your first example compiles because you are passing a parameter to all calls of 'test' and therefore the default parameter is never used. However, this for example: void test(out uint i = 5) { assert(i == 5); } void main() { uint i; test(i); //compiles test(); //cast(uint)5 is not an lvalue } Will not compile because the default parameter is required for the 2nd call to 'test' and '5' is not an lvalue (cannot be aliased). The solution: I think it would be fair to ask for the compiler to error on: void test(out uint i = 5) regardless of whether the default parameter is ever required, simply because it will never be legal to have a non lvalue default parameter to an 'out' or 'inout' parameter. At the same time perhaps this should remain valid: uint globalVar; void test(out uint i = globalVar) {} because I can imagine some useful things you can do with this. What do you think Walter? Regan-[Unknown]On Sat, 25 Feb 2006 16:21:23 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:That does not make it logical or consistent. It makes it confusing and inconsistent. Utility is not at all my concern.Ok, so lets look at the consistency of this.In other words, you're essentially saying that this makes sense: var2 = 2; var1 = var2; var1 = 1; assert(var2 == 1);No, he's saying that this makes sense: void foo(inout int var1) { var1 = 1; } int var2 = 2; foo(var2); assert(var2 == 1); Remember, 'inout' aliases the variable you pass, the parameter 'var1' is another name for the variable 'var2'. So, when you write: void foo(inout int var1 = 7) what are you saying? Lets start with what a default parameters means, in this case: void foo(int var1 = 7) {} says, if I do not get passed a variable, pass 7, in other words: foo(); is called as: foo(7); Agreed? Therefore: void foo(inout int var1 = 7) says, if I do not get passed a variable, pass 7, meaning: foo(); is called as: foo(7); Agreed? Now, as well all know you cannot pass '7' as inout because you cannot alias '7'. What I am trying to show here is that default parameters are behaving both logically and consistently, they always mean: "If I do not get passed a variable, pass X" where X is the default parameter value supplied. Further, 'inout' is behaving both logically and consistently, in all cases it aliases the parameter which is passed. The behaviour of 'in'+'default parameter' is not the same as 'inout'+'default parameter' but why should it be? IMO one is an apple and the other an orange. Regan
Feb 25 2006
On Sun, 26 Feb 2006 17:30:09 +1300, Regan Heath <regan netwin.co.nz> wrote:I didn't mean to suggest that 'in' was a replacement for what is passed, but rather that the default initialiser is a replacement for what _isn't_ passed.Oops, here I am muddying the waters, "default initialiser" should read "default parameter". Regan
Feb 25 2006
Except aliases and typedefs (exactly, as I could tell, for the reason of consistency) do not use an = sign. If they did, it would be strange and inconsistent. I am very glad they do not. Personally, I think = should be disallowed entirely for out parameters, and should work on inout parameters in the same way as it does for in ones. This would stay logical. If out int i = 5 should not compile when no parameter is passed, it should not compile when a parameter is passed - as you said. I think the usefulness of global variables, especially considering thread safety, would only grow confusing in actual and practical use. -[Unknown]On Sat, 25 Feb 2006 18:58:44 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:If that is the meaning, some symbol should be used to indicate that there is a reference being made.The symbols 'inout' and 'out' indicate an alias/reference is being made.I don't think, personally, it makes any sense to say that in is a replacement for what might be passed. It is much more like an initializer, which would never behave in that way. To me, it is unclear and unlike the rest of the language to do as you suggest.I didn't mean to suggest that 'in' was a replacement for what is passed, but rather that the default initialiser is a replacement for what _isn't_ passed.Your suggestion separates the logic of parameter defaulting from initialization completely, but they share the same syntax (as they share again with assignment.) I think this is, at best, unclear and clumsy. At worst, it is obviously inconsistent and confusing.I think you make a valid point here. default parameters, and assignment (which initialization is essentially) share the same syntax, they both use '='. It does suggest that a default parameter is an initializer, when in fact, I believe it's not that at all. That same syntax, '=', is likely the cause of this thread :)But that is more of a philosophical debate, and that will be for Walter to answer, ultimately. My point is that there is a bug here, nonetheless.I agree, my idea at the solution is below.Regardless of what you are saying, why should my initial example compile? should not compile, it shouldIt should either work as initialization, or not compile. It should not compile and do nothing. This is also unclear and inconsistent.Your first example compiles because you are passing a parameter to all calls of 'test' and therefore the default parameter is never used. However, this for example: void test(out uint i = 5) { assert(i == 5); } void main() { uint i; test(i); //compiles test(); //cast(uint)5 is not an lvalue } Will not compile because the default parameter is required for the 2nd call to 'test' and '5' is not an lvalue (cannot be aliased). The solution: I think it would be fair to ask for the compiler to error on: void test(out uint i = 5) regardless of whether the default parameter is ever required, simply because it will never be legal to have a non lvalue default parameter to an 'out' or 'inout' parameter. At the same time perhaps this should remain valid: uint globalVar; void test(out uint i = globalVar) {} because I can imagine some useful things you can do with this. What do you think Walter? Regan-[Unknown]
Feb 25 2006
Unknown W. Brackets wrote:Except aliases and typedefs (exactly, as I could tell, for the reason of consistency) do not use an = sign. If they did, it would be strange and inconsistent. I am very glad they do not. Personally, I think = should be disallowed entirely for out parameters, and should work on inout parameters in the same way as it does for in ones. This would stay logical. If out int i = 5 should not compile when no parameter is passed, it should not compile when a parameter is passed - as you said.No, it should never compile.I think the usefulness of global variables, especially considering thread safety, would only grow confusing in actual and practical use.Maybe, but noone is stoping you from implementing thread safe access to global variable if thread safety is what you need.
Feb 26 2006
On Sat, 25 Feb 2006 21:02:30 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:Personally, I think = should be disallowed entirely for out parameters, and should work on inout parameters in the same way as it does for in ones. This would stay logical.You realise 'inout' aliases the parameter in the same was as 'out' does? Regan
Feb 26 2006
I'm thinking from the "in-side". In my mind, if I leave off an out or inout parameter, I want the result to go nowhere (but might still expect the variable to exist in the function.) I don't see how this isn't logical, but I can understand how you'd disagree. You do seem to disagree; to make us both happy, perhaps only in should have default parameters allowed. -[Unknown]On Sat, 25 Feb 2006 21:02:30 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:Personally, I think = should be disallowed entirely for out parameters, and should work on inout parameters in the same way as it does for in ones. This would stay logical.You realise 'inout' aliases the parameter in the same was as 'out' does? Regan
Feb 26 2006
Unknown W. Brackets wrote:I'm thinking from the "in-side". In my mind, if I leave off an out or inout parameter, I want the result to go nowhere (but might still expect the variable to exist in the function.) I don't see how this isn't logical, but I can understand how you'd disagree.If you don't want a result the solution is easy: void func(in int x = 7) func(); All conditions satisfied: * result is going nowhere * var exists in a function * it's value is 7 The point is: if you don't need a result, then what you probably want is in and not out/inout. Out is for something else.
Feb 26 2006
Obviously that has nothing to do with what I meant. Consider: int foo(out C x, out C y, out C z); It is possible I may not want to specify a y or a z. I may however still want the return value and x. In other parts of my code, I may want x and y, or all three. Only in some places will I not want z or y. You clearly misunderstood me. Using in has absolutely nothing to do with this. Currently, a workaround would be: int foo(out C x) { C dummy1, dummy2; return foo(x, dummy1, dummy2); } But this really is going to the side a bit of the topic. -[Unknown]Unknown W. Brackets wrote:I'm thinking from the "in-side". In my mind, if I leave off an out or inout parameter, I want the result to go nowhere (but might still expect the variable to exist in the function.) I don't see how this isn't logical, but I can understand how you'd disagree.If you don't want a result the solution is easy: void func(in int x = 7) func(); All conditions satisfied: * result is going nowhere * var exists in a function * it's value is 7 The point is: if you don't need a result, then what you probably want is in and not out/inout. Out is for something else.
Feb 26 2006
Unknown W. Brackets wrote:Obviously that has nothing to do with what I meant.Uh, sorry I'm tired.Consider: int foo(out C x, out C y, out C z); It is possible I may not want to specify a y or a z. I may however still want the return value and x. In other parts of my code, I may want x and y, or all three. Only in some places will I not want z or y. You clearly misunderstood me. Using in has absolutely nothing to do with this.I see that now:Currently, a workaround would be: int foo(out C x) { C dummy1, dummy2; return foo(x, dummy1, dummy2); }No: a workaround would be: private int dummy1, dummy2; void foo(out int x = dummy1, out int y = dummy2, out int z = dummy3){...} int foo(out C x) { return foo(x); } It complicates library code just a little but simplifies users code.But this really is going to the side a bit of the topic.I thought the topic was initialization of out parameters.
Feb 26 2006
Yes, but this is a topic about a bug. We are no longer really talking about the bug. If you used your workaround, you would have: 1. Extra global variables somewhere in memory, which may not be desirable. 2. Uninitialized variables, from what I can tell (out parameters are normally initialized to their default state at the beginning of the function.) This may cause unexpected/hard-to-reproduce bugs. 3. Requirements to use synchronized blocks around accesses to the variables, which would normally not be necessary with typical out parameters. This would be needed because the function may depend on the global variables not changing mid-function, but the function might get called numerous times concurrently in multiple threads. It's true that programming involves the above all the time, but they can all be avoided in this case by not using your described method. As such, I consider them flaws in the proposed method. -[Unknown]Unknown W. Brackets wrote:Obviously that has nothing to do with what I meant.Uh, sorry I'm tired.Consider: int foo(out C x, out C y, out C z); It is possible I may not want to specify a y or a z. I may however still want the return value and x. In other parts of my code, I may want x and y, or all three. Only in some places will I not want z or y. You clearly misunderstood me. Using in has absolutely nothing to do with this.I see that now:Currently, a workaround would be: int foo(out C x) { C dummy1, dummy2; return foo(x, dummy1, dummy2); }No: a workaround would be: private int dummy1, dummy2; void foo(out int x = dummy1, out int y = dummy2, out int z = dummy3){...} int foo(out C x) { return foo(x); } It complicates library code just a little but simplifies users code.But this really is going to the side a bit of the topic.I thought the topic was initialization of out parameters.
Feb 26 2006
On Sun, 26 Feb 2006 14:44:57 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:Yes, but this is a topic about a bug. We are no longer really talking about the bug. If you used your workaround, you would have: 1. Extra global variables somewhere in memory, which may not be desirable.True, however you can use the same default global for every parameter of the same type provided the 'out' contract of the function does not check them (which is something you will know and can work around), eg. int dontCare; int test(out int a = dontCare, out int b = dontCare, out int c = dontCare) { ... } You can do this because the dummy globals are never 'read' by anything at any time.2. Uninitialized variables, from what I can tell (out parameters are normally initialized to their default state at the beginning of the function.) This may cause unexpected/hard-to-reproduce bugs.'out' and dummy globals do not prevent the init of the out parameter: import std.stdio; int global = 5; void test(out int a = global) { writefln(a); } void main() { writefln(global); test(); } Output: 5 03. Requirements to use synchronized blocks around accesses to the variablesWhy? Given that value of an 'out' variable is never 'read' by anyone at any time it does not matter what value it has at any given time, or even that it has any sensible value at all. The same cannot be said for 'inout' however. For 'inout' you would need to protect access to the global. For 'inout' your points above are valid. You would need to protect access to the global, but, as Ivan mentioned that may be exactly what you want. In the end are we arguing about the utility of each set of behaviour or the logic of it? If we're arguing about the logic, my opinion remains that the current behaviour is logical given the following rules: "out and inout _always_ alias/reference the parameter passed" "a default parameter is passed when no parameter is given explicitly" "a constant cannot be passed by reference" In order to implement inout how you describe (as 'in' sometimes) you'd with other instances of 'inout'. The problem seems mainly to be the perception that a default parameter is a default initializer and that is simply incorrect in the general case. It is only true for value types passed as 'in' parameters. Take for example: void test(int* a = 5) {} //cannot implicitly convert expression (5) of type int to int* you would never expect that to work, right? This is essentially identical to: void test(inout int a = 5) {} Regan
Feb 26 2006
Given the following example: class X { int bar; } int foo(out X var) { var.bar = 5; assert(var.bar == 5); } Look at that, an out parameter - being read? Amazing, I've done the unthinkable. If a variable is a pointer, it should be a pointer. Classes, as reference types, are clear because they are always pointers. However, consider the following: import std.stdio; int main() { int x; test(x); return 0; } void test(out int x) { writefln(typeid(typeof(x))); } This code clearly identifies x as an int. If it is an int, it should be an int, and it should always be an int. I mean, that's just common sense. If an animal is a moose, it should not be a giraffe. We learn this in kindergarten. In every other way, out and inout parameters are treated as moose. ONLY when they receive a default parameter are they being treated as giraffe. This is inconsistent. They should only ever be treated as one animal: as a giraffe, or as a moose. There is no girmooffe. I've really grown quite tired with your patronizing and condescending tone, and you are reminding me exactly what I dislike about this newsgroup and therefore D; the people who seem to surround it. The language seems okay but I honestly remember why I don't use it as often every time I get in a conversation with one of you people. -[Unknown]On Sun, 26 Feb 2006 14:44:57 -0800, Unknown W. Brackets <unknown simplemachines.org> wrote:Yes, but this is a topic about a bug. We are no longer really talking about the bug. If you used your workaround, you would have: 1. Extra global variables somewhere in memory, which may not be desirable.True, however you can use the same default global for every parameter of the same type provided the 'out' contract of the function does not check them (which is something you will know and can work around), eg. int dontCare; int test(out int a = dontCare, out int b = dontCare, out int c = dontCare) { ... } You can do this because the dummy globals are never 'read' by anything at any time.2. Uninitialized variables, from what I can tell (out parameters are normally initialized to their default state at the beginning of the function.) This may cause unexpected/hard-to-reproduce bugs.'out' and dummy globals do not prevent the init of the out parameter: import std.stdio; int global = 5; void test(out int a = global) { writefln(a); } void main() { writefln(global); test(); } Output: 5 03. Requirements to use synchronized blocks around accesses to the variablesWhy? Given that value of an 'out' variable is never 'read' by anyone at any time it does not matter what value it has at any given time, or even that it has any sensible value at all. The same cannot be said for 'inout' however. For 'inout' you would need to protect access to the global. For 'inout' your points above are valid. You would need to protect access to the global, but, as Ivan mentioned that may be exactly what you want. In the end are we arguing about the utility of each set of behaviour or the logic of it? If we're arguing about the logic, my opinion remains that the current behaviour is logical given the following rules: "out and inout _always_ alias/reference the parameter passed" "a default parameter is passed when no parameter is given explicitly" "a constant cannot be passed by reference" In order to implement inout how you describe (as 'in' sometimes) you'd with other instances of 'inout'. The problem seems mainly to be the perception that a default parameter is a default initializer and that is simply incorrect in the general case. It is only true for value types passed as 'in' parameters. Take for example: void test(int* a = 5) {} //cannot implicitly convert expression (5) of type int to int* you would never expect that to work, right? This is essentially identical to: void test(inout int a = 5) {} Regan
Feb 26 2006
Unknown W. Brackets wrote:Given the following example: class X { int bar; } int foo(out X var) { var.bar = 5; assert(var.bar == 5); } Look at that, an out parameter - being read? Amazing, I've done the unthinkable.Don't see what the problem is, you as an author of foo know what you are doing so know if there should be only one dummy variable or more.If a variable is a pointer, it should be a pointer.Agree.Classes, as reference types, are clear because they are always pointers.Agree.However, consider the following: import std.stdio; int main() { int x; test(x); return 0; } void test(out int x) { writefln(typeid(typeof(x))); } This code clearly identifies x as an int. If it is an int, it should be an int, and it should always be an int. I mean, that's just common sense. If an animal is a moose, it should not be a giraffe. We learn this in kindergarten.Well in this case it is a moose&. D handles references a little strange meaning they aren't really real types, but they are still here. An out parameter means int is passed by reference. You should think about it as: void test(int& x) in C++.In every other way, out and inout parameters are treated as moose.Not really. Can the original moose changed when you pass it as in? No. Can it be changed when you pass it as out, or inout. Yes. So they aren't really treated the same.I've really grown quite tired with your patronizing and condescending tone, and you are reminding me exactly what I dislike about this newsgroup and therefore D; the people who seem to surround it. The language seems okay but I honestly remember why I don't use it as often every time I get in a conversation with one of you people.I am sorry if anything I said seams patronizing or condescending. I can assure you I didn't mean it that way. I was just trying to explain my point of view. Maybe my imperfect English is a cause for occasional bad choise of words that can be misinterpreted. Once again. I am sorry. Maybe it is best to stop the conversation.
Feb 26 2006
On Mon, 27 Feb 2006 01:41:04 +0100, Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> wrote:I couldn't have put it better Ivan. "[Unknown]" you have my apologies also. ReganI've really grown quite tired with your patronizing and condescending tone, and you are reminding me exactly what I dislike about this newsgroup and therefore D; the people who seem to surround it. The language seems okay but I honestly remember why I don't use it as often every time I get in a conversation with one of you people.I am sorry if anything I said seams patronizing or condescending. I can assure you I didn't mean it that way. I was just trying to explain my point of view.
Feb 26 2006
Unknown W. Brackets wrote:Yes, but this is a topic about a bug. We are no longer really talking about the bug.Do we agree then that the bug is that void f(out int x = 5) isn't an error?If you used your workaround, you would have: 1. Extra global variables somewhere in memory, which may not be desirable.But as Regan said, possibly only one for each type.2. Uninitialized variables, from what I can tell (out parameters are normally initialized to their default state at the beginning of the function.) This may cause unexpected/hard-to-reproduce bugs.Same happens here. void f(out int x = globalX) -> globalX is initialized to int.init. No bugs here.3. Requirements to use synchronized blocks around accesses to the variables, which would normally not be necessary with typical out parameters. This would be needed because the function may depend on the global variables not changing mid-function, but the function might get called numerous times concurrently in multiple threads.I agree this is a problem in multithreaded enviroment.It's true that programming involves the above all the time, but they can all be avoided in this case by not using your described method. As such, I consider them flaws in the proposed method.But there isn't any other way to solve what you wanted? Or is there? I mean wanting not allways to pass out arguments to a function. Atleast not other way without changing the language so that out default params are made strange and inconsistent. But I agree this discussion sholud probably end soon :)
Feb 26 2006
On Sun, 19 Feb 2006 17:53:45 -0800, Unknown W. Brackets wrote:The spec says: out parameters are set to the default initializer for the type of it. Which makes perfect sense, and works just fine. The trick comes in when I try some parameter initialization.I'm writing this without reading the entire thread, so please excuse me if I'm out of line. I also preface these remarks by noting that the documentation is exceedingly light on the whole 'default parameter' specification. Functions: "A function parameter's default value is not inherited ..." Change log for v0.92: "Added default arguments to function parameters. Semantics are like C++." Anyhow, it seems that you are thinking in terms of "initialize" rather than "default". The difference is that "default" (which is what I believe D is implementing) is invoked by the compiler when a omit a parameter on the call, and "initialize" is when the compiler applies a value to a parameter which you have not omitted, and I don't think the D has implemented this concept. foo(in int a) // foo gets (a copy) the value of 'a'. foo(in int a = 5) // foo gets 'a' if you pass it, // otherwise it gets the literal 5 foo(out int a) // foo gets (a reference to) the value of 'a' and // sets the value of 'a' to the default initializer for // for 'int'. foo(out int a = 5) // foo gets a reference to 'a' if you pass it etc..., // otherwise it gets a reference to the literal 5 // and sets the value of 5 to 0 // (which doesn't make sense to me) foo(inout int a) // foo gets (a reference to) the value of 'a'. foo(inout int a = 5) // foo gets a reference to 'a' if you pass it, // otherwise it gets a reference to the literal 5 // (which doesn't make sense to me) So I think that defining default parameters for 'out' and 'inout' arguments should be a compile-time error, because in these cases the called program will be receiving the address of a literal. Can Walter clarify the intent of the default parameter syntax when used in conjunction with 'out' and 'inout'? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 27/02/2006 1:38:08 PM
Feb 26 2006
Derek Parnell wrote:On Sun, 19 Feb 2006 17:53:45 -0800, Unknown W. Brackets wrote:Who in his right mind would read the entire thread. :)The spec says: out parameters are set to the default initializer for the type of it. Which makes perfect sense, and works just fine. The trick comes in when I try some parameter initialization.I'm writing this without reading the entire thread, so please excuse me if I'm out of line.I also preface these remarks by noting that the documentation is exceedingly light on the whole 'default parameter' specification. Functions: "A function parameter's default value is not inherited ..." Change log for v0.92: "Added default arguments to function parameters. Semantics are like C++." Anyhow, it seems that you are thinking in terms of "initialize" rather than "default". The difference is that "default" (which is what I believe D is implementing) is invoked by the compiler when a omit a parameter on the call, and "initialize" is when the compiler applies a value to a parameter which you have not omitted, and I don't think the D has implemented this concept.Correct.foo(in int a) // foo gets (a copy) the value of 'a'. foo(in int a = 5) // foo gets 'a' if you pass it, // otherwise it gets the literal 5 foo(out int a) // foo gets (a reference to) the value of 'a' and // sets the value of 'a' to the default initializer for // for 'int'. foo(out int a = 5) // foo gets a reference to 'a' if you pass it etc..., // otherwise it gets a reference to the literal 5 // and sets the value of 5 to 0 // (which doesn't make sense to me)I must agree this doesn't make sense. But this does: foo(out int a = globalA) //if you pass something a reference to it is passed //if you don't a reference toa global int 'globalA' is passed This (to me) makes sense, is usefull, and is implemented.foo(inout int a) // foo gets (a reference to) the value of 'a'. foo(inout int a = 5) // foo gets a reference to 'a' if you pass it, // otherwise it gets a reference to the literal 5 // (which doesn't make sense to me) So I think that defining default parameters for 'out' and 'inout' arguments should be a compile-time error, because in these cases the called program will be receiving the address of a literal.I think constant arguments for default out/inout arguments shuld be an error, non constant don't need to be.Can Walter clarify the intent of the default parameter syntax when used in conjunction with 'out' and 'inout'?This would be a good thing.
Feb 26 2006