digitalmars.D.bugs - [Bug 191] New: Cannot refer to member variable in default value for method parameter
- d-bugmail puremagic.com (35/35) Jun 11 2006 http://d.puremagic.com/bugzilla/show_bug.cgi?id=191
- Jarrett Billingsley (3/7) Jun 11 2006 Is this even in the spec? I had no idea you were supposed to be allowed...
- Deewiant (15/18) Jun 11 2006 All I can find about default parameters in the spec is at the "Functions...
- Jarrett Billingsley (41/51) Jun 11 2006 Oh, wow, I didn't know that it allowed you to do this with other kinds o...
- Deewiant (11/23) Jun 11 2006 If it does it like that - which _would_ be simpler and possibly faster f...
- BCS (15/27) Jun 12 2006 [...]
- Oskar Linde (10/46) Jun 12 2006 I guess this is the intended behavior. The default argument is evaluated...
- Bruno Medeiros (11/47) Jun 13 2006 Hum, quite a catch you got there! Not only should it be better
- BCS (13/40) Jun 13 2006 hee hee, their is one use for this
- Don Clugston (20/35) Jun 14 2006 I'm almost certain that default values should work that way. They should...
- Bruno Medeiros (13/54) Jun 17 2006 You meant:
- Don Clugston (8/63) Jun 23 2006 But the 'goo' example does compile. Why is there a difference between
- Bruno Medeiros (22/86) Jun 23 2006 What I was trying to say, in the general sense, is that by making
- BCS (13/58) Jun 23 2006 Things get worse when auto is used. you end up with a type that is
- Bruno Medeiros (7/21) Jun 12 2006 Which then means this is not a bug.
- Deewiant (4/22) Jun 12 2006 If you ask me, it's both of the latter. The documentation certainly need...
http://d.puremagic.com/bugzilla/show_bug.cgi?id=191 Summary: Cannot refer to member variable in default value for method parameter Product: D Version: 0.160 Platform: PC OS/Version: Windows Status: NEW Keywords: rejects-valid Severity: normal Priority: P3 Component: DMD AssignedTo: bugzilla digitalmars.com ReportedBy: deewiant gmail.com -- class c { int x = 5; int foo(int a = x) { return a; } } void main() { assert ((new c).foo() == 5); } -- The above code does not compile, producing the error "need 'this' to access member x". Obliging by changing "int a = x" to "int a = this.x" changes the error to "'this' is only allowed in non-static member functions" followed by "this for x needs to be type c not type int". It can be worked around by removing the default value and manually overriding foo with "int foo() { return foo(x); }", but this is a needless annoyance and precisely what default values are there for. It might be worth noting that this is a longstanding bug which bit me for the first time with DMD 0.128: http://www.digitalmars.com/d/archives/digitalmars/D/bugs/4532.html --
Jun 11 2006
<d-bugmail puremagic.com> wrote in message news:bug-191-It might be worth noting that this is a longstanding bug which bit me for the first time with DMD 0.128: http://www.digitalmars.com/d/archives/digitalmars/D/bugs/4532.htmlIs this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.
Jun 11 2006
Jarrett Billingsley wrote:Is this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. The changelog for DMD 0.92 also says "Added default arguments to function parameters. Semantics are like C++." but that's it. After some testing, it seems that that would actually explain it: C++ doesn't allow it. For what it's worth, I don't see any sense in this restriction - how is a class's member different from any other variable in this situation? Especially since the workaround is so simple, and isn't that all that default parameters are meant to do - overload the method into a form which takes one less parameter and passes the default value to the original? They don't have to implement it that way, but that's how I see the semantics of it. And I'm not a compiler writer, but it doesn't seem very difficult to implement either.
Jun 11 2006
"Deewiant" <deewiant.doesnotlike.spam gmail.com> wrote in message news:e6hp54$a2d$1 digitaldaemon.com...For what it's worth, I don't see any sense in this restriction - how is a class's member different from any other variable in this situation?Oh, wow, I didn't know that it allowed you to do this with other kinds of variables. I always thought that the default parameter initializer had to evaluate to a constant!Especially since the workaround is so simple, and isn't that all that default parameters are meant to do - overload the method into a form which takes one less parameter and passes the default value to the original?Well, as far as I know, that's not how the compiler implements it. It just keeps one copy of the function, and when it comes across a call that doesn't have all the parameters, it rewrites the function call so that the unwritten parameters use the parameter initializer. So there's no actual overloading going on.They don't have to implement it that way, but that's how I see the semantics of it.That might be the problem - depending on whether or not the default argument was a member variable, it might end up adding complexity to the default argument mechanism, since the value of a local variable can't really be determined until _after_ the function has been called with a 'this' reference. It would be like trying to do something like: void func(int[] x, int y = x[5]) Since x[5] can't be determined until after func() has been called, it would have to have multiple code paths for func; one which would be for taking a y, and one which would determine y from the x argument. Though it could possibly be added into the current mechanism, if you had a class like: class A { int x; void func(int y = x) { writefln(y); } } Then if you called func: A a = new A; a.func(); The compiler would know that the default initializer for the first argument is the member variable x, and would then rewrite the call as: a.func(a.x); Possible, but kind of complicated. Overloading a function to implement the default parameter with a member variable as the initializer seems like a simple enough workaround until (if?) this is fixed. I agree that it should be possible for consistency with the ability to use other variables as default argument initializers, but I don't know how many extra levels of complexity it adds.
Jun 11 2006
Jarrett Billingsley wrote:"Deewiant" <deewiant.doesnotlike.spam gmail.com> wrote in message news:e6hp54$a2d$1 digitaldaemon.com...If it does it like that - which _would_ be simpler and possibly faster for the non-class-member case - I can sort of see why it might be tricky for the class-member case. But it's still not impossible, like you pointed out: calling a method, the compiler knows which class instance's method is being called and can take the member from the same instance. It does, however, become impossible if the member is private or protected, and the caller can't access the variable. Which, come to think of it, is probably why it's not allowed in C++. Simulating that extra overloaded method does work even in that case, though.Especially since the workaround is so simple, and isn't that all that default parameters are meant to do - overload the method into a form which takes one less parameter and passes the default value to the original?Well, as far as I know, that's not how the compiler implements it. It just keeps one copy of the function, and when it comes across a call that doesn't have all the parameters, it rewrites the function call so that the unwritten parameters use the parameter initializer. So there's no actual overloading going on.
Jun 11 2006
Deewiant wrote:Jarrett Billingsley wrote:[...] Is this correct behavior? If it is it needs to be documeted better. <code> import std.stdio; class C { int foo(int x = 1){return x;} } class D:C { int foo(int x = 2){return x;} } void main() { C c = new D; D d = cast(D)c; writef(c.foo,\n); // prints 1 (?) writef(d.foo,\n); // prints 2 } </code>Is this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. The changelog for DMD 0.92 also says "Added default arguments to function parameters. Semantics are like C++." but that's it.
Jun 12 2006
BCS skrev:Deewiant wrote:I guess this is the intended behavior. The default argument is evaluated at call site and passed to the function. main() calling c.foo has no way of knowing (at compile time) what derived class instance c may hold (there is no vtbl for default arguments). I see how this can lead to hard to find bugs. I.e. if the default argument is changed in the base class, but not in a (maybe independently developed) derived class. It may be better if D inherited default values and forbade them to be redefined in derived classes. /OskarJarrett Billingsley wrote:[...] Is this correct behavior? If it is it needs to be documeted better. <code> import std.stdio; class C { int foo(int x = 1){return x;} } class D:C { int foo(int x = 2){return x;} } void main() { C c = new D; D d = cast(D)c; writef(c.foo,\n); // prints 1 (?) writef(d.foo,\n); // prints 2 } </code>Is this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. The changelog for DMD 0.92 also says "Added default arguments to function parameters. Semantics are like C++." but that's it.
Jun 12 2006
BCS wrote:Deewiant wrote:Hum, quite a catch you got there! Not only should it be better documented, but maybe it shouldn't work this way. Perhaps the default values should be set not at the call site, but by the function itself (thus depending on it's run-time type, and not it's compile-time type), or maybe it could be as Oskar's idea ("if D inherited default values and forbade them to be redefined in derived classes") -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DJarrett Billingsley wrote:[...] Is this correct behavior? If it is it needs to be documeted better. <code> import std.stdio; class C { int foo(int x = 1){return x;} } class D:C { int foo(int x = 2){return x;} } void main() { C c = new D; D d = cast(D)c; writef(c.foo,\n); // prints 1 (?) writef(d.foo,\n); // prints 2 } </code>Is this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. The changelog for DMD 0.92 also says "Added default arguments to function parameters. Semantics are like C++." but that's it.
Jun 13 2006
Bruno Medeiros wrote:BCS wrote:hee hee, their is one use for this // never call with i set explicitly class C { abstract void doSomthing(char[] msg, int i=0); } class D:C { abstract void doSomthing(char[] msg, int i=1); } class E:D { abstract void doSomthing(char[] msg, int i=2); } class F:E { void doSomthing(char[] msg, int i=3) { writef(`doSomthing("%s") as class %c`\n,msg, 'C'+i); } } Now we known the type of the reference used to call doSomthing. (I pray I never have reason to use this.)<code> import std.stdio; class C { int foo(int x = 1){return x;} } class D:C { int foo(int x = 2){return x;} } void main() { C c = new D; D d = cast(D)c; writef(c.foo,\n); // prints 1 (?) writef(d.foo,\n); // prints 2 } </code>Hum, quite a catch you got there! Not only should it be better documented, but maybe it shouldn't work this way. Perhaps the default values should be set not at the call site, but by the function itself (thus depending on it's run-time type, and not it's compile-time type), or maybe it could be as Oskar's idea ("if D inherited default values and forbade them to be redefined in derived classes")
Jun 13 2006
Bruno Medeiros wrote:BCS wrote:...Deewiant wrote:All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. TheI'm almost certain that default values should work that way. They should just be syntactic sugar for overloaded functions. Right now, they have the same problem which C++ has -- there's no way that a template can find out what the default values are, and the default values can't be used by function pointers or delegates. So for example, void foo(int a, int b=2, int c=3) {} void goo(int a, int b, int c) { } void goo(int a, int b) { goo(a, b, 3); } void goo(int a) { goo(a, 2, 3); } void function(int) boo; foo(7); // ok goo(7); // ok boo = goo; // ok boo(5); boo = foo; // doesn't compile -- why not? boo(5); or maybe it could be as Oskar's idea ("if DHum, quite a catch you got there! Not only should it be better documented, but maybe it shouldn't work this way. Perhaps the default values should be set not at the call site, but by the function itself (thus depending on it's run-time type, and not it's compile-time type),inherited default values and forbade them to be redefined in derived classes")
Jun 14 2006
Don Clugston wrote:Bruno Medeiros wrote:You meant: boo = &goo; // ok boo(5); boo = &foo; // doesn't compile -- why not? Anyway, "Why not?" ? How could that compile? Even with that syntatic sugar the problem would subsist: remember that the expression (&foo) has to be evaluable by itself, and if there are many overloads of foo there is no way (with that syntax at least) to choose the correct one. (DMD currently chooses the lexically first overload) -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DBCS wrote:....Deewiant wrote:All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. TheI'm almost certain that default values should work that way. They should just be syntactic sugar for overloaded functions. Right now, they have the same problem which C++ has -- there's no way that a template can find out what the default values are, and the default values can't be used by function pointers or delegates. So for example, void foo(int a, int b=2, int c=3) {} void goo(int a, int b, int c) { } void goo(int a, int b) { goo(a, b, 3); } void goo(int a) { goo(a, 2, 3); } void function(int) boo; foo(7); // ok goo(7); // ok boo = goo; // ok boo(5); boo = foo; // doesn't compile -- why not? boo(5);Hum, quite a catch you got there! Not only should it be better documented, but maybe it shouldn't work this way. Perhaps the default values should be set not at the call site, but by the function itself (thus depending on it's run-time type, and not it's compile-time type),
Jun 17 2006
Bruno Medeiros wrote:Don Clugston wrote:But the 'goo' example does compile. Why is there a difference between 'goo' and 'foo'? AFAIK, default parameters were introduced (in C++) purely as syntactic sugar, and AFAIK they are only ever used in that way. I think they should be just syntactic sugar. As they exist in both D and C++, they are a quirky language primitive which cannot be emulated in any other way. They lead to some horrible corner cases.Bruno Medeiros wrote:You meant: boo = &goo; // ok boo(5); boo = &foo; // doesn't compile -- why not? Anyway, "Why not?" ? How could that compile? Even with that syntatic sugar the problem would subsist: remember that the expression (&foo) has to be evaluable by itself, and if there are many overloads of foo there is no way (with that syntax at least) to choose the correct one. (DMD currently chooses the lexically first overload)BCS wrote:....Deewiant wrote:All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. TheI'm almost certain that default values should work that way. They should just be syntactic sugar for overloaded functions. Right now, they have the same problem which C++ has -- there's no way that a template can find out what the default values are, and the default values can't be used by function pointers or delegates. So for example, void foo(int a, int b=2, int c=3) {} void goo(int a, int b, int c) { } void goo(int a, int b) { goo(a, b, 3); } void goo(int a) { goo(a, 2, 3); } void function(int) boo; foo(7); // ok goo(7); // ok boo = goo; // ok boo(5); boo = foo; // doesn't compile -- why not? boo(5);Hum, quite a catch you got there! Not only should it be better documented, but maybe it shouldn't work this way. Perhaps the default values should be set not at the call site, but by the function itself (thus depending on it's run-time type, and not it's compile-time type),
Jun 23 2006
Don Clugston wrote:Bruno Medeiros wrote:What I was trying to say, in the general sense, is that by making default parameters be just sugar for function overloads, we become susceptible to the problems of ambiguous homonymous function overloads (which in fact, is a separate issue, and the one I was more worried about) I'm not saying default parameters shouldn't be syntactic sugar because of that, I'm just pointing it out. As for the ambiguous overloads issue: in the example above, I said "DMD currently chooses the lexically first overload" but that is not entirely correct. If that was so, then: boo = &goo; // ok would not work as in the example above, yet it does. This can only be an ugly special case hack, and a huge breach of consistency, since the following doesn't work: (&goo) (1, 2); // Expected func with 2 params auto temp = &goo; boo = temp; // Type mismatch, expected void function(int) This worries me.Don Clugston wrote:But the 'goo' example does compile. Why is there a difference between 'goo' and 'foo'?Bruno Medeiros wrote:You meant: boo = &goo; // ok boo(5); boo = &foo; // doesn't compile -- why not? Anyway, "Why not?" ? How could that compile? Even with that syntatic sugar the problem would subsist: remember that the expression (&foo) has to be evaluable by itself, and if there are many overloads of foo there is no way (with that syntax at least) to choose the correct one. (DMD currently chooses the lexically first overload)BCS wrote:....Deewiant wrote:All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. TheI'm almost certain that default values should work that way. They should just be syntactic sugar for overloaded functions. Right now, they have the same problem which C++ has -- there's no way that a template can find out what the default values are, and the default values can't be used by function pointers or delegates. So for example, void foo(int a, int b=2, int c=3) {} void goo(int a, int b, int c) { } void goo(int a, int b) { goo(a, b, 3); } void goo(int a) { goo(a, 2, 3); } void function(int) boo; foo(7); // ok goo(7); // ok boo = goo; // ok boo(5); boo = foo; // doesn't compile -- why not? boo(5);Hum, quite a catch you got there! Not only should it be better documented, but maybe it shouldn't work this way. Perhaps the default values should be set not at the call site, but by the function itself (thus depending on it's run-time type, and not it's compile-time type),AFAIK, default parameters were introduced (in C++) purely as syntactic sugar, and AFAIK they are only ever used in that way. I think they should be just syntactic sugar. As they exist in both D and C++, they are a quirky language primitive which cannot be emulated in any other way. They lead to some horrible corner cases.Yes, like that problem with overloading default parameters. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jun 23 2006
Bruno Medeiros wrote:Don Clugston wrote:Things get worse when auto is used. you end up with a type that is indeterminable without knowing the lexical order of function decelerations. I that case code validity is dependent on the order of other code. int foo(long i, int j){return i+j;} char[] foo(int i){return i;} auto fp = &foo; auto i = foo(0,0); // legal unless foo's are reversed What is need is a way to specify a particular function as a pointer. auto fp1 = &foo(int); auto fp2 = &foo(long,int); // function don't run assert(fp1 != fp2);Bruno Medeiros wrote: I'm almost certain that default values should work that way. They should just be syntactic sugar for overloaded functions. Right now, they have the same problem which C++ has -- there's no way that a template can find out what the default values are, and the default values can't be used by function pointers or delegates. So for example, void foo(int a, int b=2, int c=3) {} void goo(int a, int b, int c) { } void goo(int a, int b) { goo(a, b, 3); } void goo(int a) { goo(a, 2, 3); } void function(int) boo; foo(7); // ok goo(7); // ok boo = goo; // ok boo(5); boo = foo; // doesn't compile -- why not? boo(5);You meant: boo = &goo; // ok boo(5); boo = &foo; // doesn't compile -- why not? Anyway, "Why not?" ? How could that compile? Even with that syntatic sugar the problem would subsist: remember that the expression (&foo) has to be evaluable by itself, and if there are many overloads of foo there is no way (with that syntax at least) to choose the correct one. (DMD currently chooses the lexically first overload)
Jun 23 2006
Deewiant wrote:Jarrett Billingsley wrote:Which then means this is not a bug. What shall it be now? (dropped issue?, documentation clarification request?, enhancement request?) -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DIs this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. The changelog for DMD 0.92 also says "Added default arguments to function parameters. Semantics are like C++." but that's it. After some testing, it seems that that would actually explain it: C++ doesn't allow it.
Jun 12 2006
Bruno Medeiros wrote:Deewiant wrote:If you ask me, it's both of the latter. The documentation certainly needs improvement in this regard, and I certainly want to be able to use class members as default parameters. <g>Jarrett Billingsley wrote:Which then means this is not a bug. What shall it be now? (dropped issue?, documentation clarification request?, enhancement request?)Is this even in the spec? I had no idea you were supposed to be allowed to use members as default parameters.All I can find about default parameters in the spec is at the "Functions" page, where they pop out of the blue in the phrase "A function parameter's default value is not inherited", which is all that's said about them. The changelog for DMD 0.92 also says "Added default arguments to function parameters. Semantics are like C++." but that's it. After some testing, it seems that that would actually explain it: C++ doesn't allow it.
Jun 12 2006