digitalmars.D - Weird template error
- Brian (24/24) Nov 18 2008 I get this (minor) error using dmd 1.036, I don't know if it's been
- Jarrett Billingsley (6/27) Nov 18 2008 This is just another example of the property sugar being subpar. With
- Andrei Alexandrescu (3/37) Nov 19 2008 I think (in this particular case) it's only about a compiler bug.
- Denis Koroskin (25/62) Nov 19 2008 But you are well aware of _other_ cases in which you _have to_ put an
- Brian (21/21) Nov 19 2008 I don't understand why we wouldn't want properties either. Another issu...
- Jarrett Billingsley (7/27) Nov 19 2008 That one's trickier, even if you did have properties. Even "true"
- Nick Sabalausky (30/65) Nov 25 2008 class Foo
- Jarrett Billingsley (6/17) Nov 25 2008 I considered this, but what if your setter/getter had some kind of
- Nick Sabalausky (39/58) Nov 26 2008 I thought about that too, but the only realistic examples of that I can
- Jarrett Billingsley (4/35) Nov 26 2008 It would also make it difficult to have virtual methods with ref
- Nick Sabalausky (8/52) Nov 26 2008 But how often are "inout" params really used anyway? Plus, unless there'...
- Jarrett Billingsley (5/9) Nov 26 2008 No; the problem manifests itself whenever separate compilation is used
- Janderson (3/31) Nov 19 2008 Some good points.
- Chad J (6/11) Nov 20 2008 ...
- Gide Nwawudu (4/13) Nov 21 2008 http://www.digitalmars.com/d/archives/digitalmars/D/Top_5_77130.html
- Michel Fortin (30/45) Nov 21 2008 As much as I like the no-parens function call syntax, I have to agree
- Nick Sabalausky (23/67) Nov 25 2008 That's why I like the consistency other languages have of:
- bearophile (9/14) Nov 25 2008 I agree, this is better (in Python there's such syntax).
- bearophile (10/13) Nov 27 2008 It sounds nice, but then this is what may happen:
- Steven Schveighoffer (8/15) Nov 20 2008 Yes, one that would not have existed without the ambiguity that is now
- Andrei Alexandrescu (5/11) Nov 19 2008 Something odd happened. I saw a different message from you (longer and a...
- Denis Koroskin (8/18) Nov 19 2008 I guess it's at your side 'cause I didn't edit my message and it is full...
I get this (minor) error using dmd 1.036, I don't know if it's been discovered or not. test.d(20): Error: template foo!(int) is not a member of actor.world test.d(20): Error: function expected before (), not 0 of type int // And heres the code that causes it class World { public void foo(T)() { } } class Actor { World _world; public World world() { return this._world; } } void main() { auto actor = new Actor; actor._world = new World; actor.world().foo!(int)(); // This works fine actor.world.foo!(int)(); // This causes the error }
Nov 18 2008
On Wed, Nov 19, 2008 at 12:14 AM, Brian <digitalmars brianguertin.com> wrote:I get this (minor) error using dmd 1.036, I don't know if it's been discovered or not. test.d(20): Error: template foo!(int) is not a member of actor.world test.d(20): Error: function expected before (), not 0 of type int // And heres the code that causes it class World { public void foo(T)() { } } class Actor { World _world; public World world() { return this._world; } } void main() { auto actor = new Actor; actor._world = new World; actor.world().foo!(int)(); // This works fine actor.world.foo!(int)(); // This causes the error }This is just another example of the property sugar being subpar. With real properties, this would not happen. However, as it is, "actor.world.foo!(int)()" parses as an attempt to access "foo!(int)()" from the _method_ designated by "actor.world", _not_ from the return value of actor.world().
Nov 18 2008
Jarrett Billingsley wrote:On Wed, Nov 19, 2008 at 12:14 AM, Brian <digitalmars brianguertin.com> wrote:I think (in this particular case) it's only about a compiler bug. AndreiI get this (minor) error using dmd 1.036, I don't know if it's been discovered or not. test.d(20): Error: template foo!(int) is not a member of actor.world test.d(20): Error: function expected before (), not 0 of type int // And heres the code that causes it class World { public void foo(T)() { } } class Actor { World _world; public World world() { return this._world; } } void main() { auto actor = new Actor; actor._world = new World; actor.world().foo!(int)(); // This works fine actor.world.foo!(int)(); // This causes the error }This is just another example of the property sugar being subpar. With real properties, this would not happen. However, as it is, "actor.world.foo!(int)()" parses as an attempt to access "foo!(int)()" from the _method_ designated by "actor.world", _not_ from the return value of actor.world().
Nov 19 2008
On Wed, 19 Nov 2008 19:44:38 +0300, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Jarrett Billingsley wrote:But you are well aware of _other_ cases in which you _have to_ put an extra pair of parens to access some property method/field thus broking an encapsulation and preventing the class designer to replace properties with fields and vice versa at a later stage. It's simply broken! You say that empty pair of parens is equivalent to none of them and thus it is allowed to omit them, but it's not true at all. There are lots of examples where "auto foo = bar();" != "auto foo = bar;" and "auto foo = obj.bar();" != "auto foo = obj.bar;" (delegates, class/struct instances with overloaded opCall, etc). - such a duality is confusing (when may you omit the parens and when you may not?) - it makes the language more complex (rules are so complex that hardly anyone fully understands them) - it leads to code inconsistency (half of the programmers remove an "extra" pair of parens and other half preserve them) - it is a source of many compiler bugs (this and lots of related ones) - it contributes to user code bugs that are hard to find at times ("oops, I missed a pair of parens. God, I thougth that they were optional"). a recent "Top 5 D problems" poll and now that a Tango/Phobos common I really wish I could understand Walter arguments against proper properties in D...On Wed, Nov 19, 2008 at 12:14 AM, Brian <digitalmars brianguertin.com> wrote:I think (in this particular case) it's only about a compiler bug. AndreiI get this (minor) error using dmd 1.036, I don't know if it's been discovered or not. test.d(20): Error: template foo!(int) is not a member of actor.world test.d(20): Error: function expected before (), not 0 of type int // And heres the code that causes it class World { public void foo(T)() { } } class Actor { World _world; public World world() { return this._world; } } void main() { auto actor = new Actor; actor._world = new World; actor.world().foo!(int)(); // This works fine actor.world.foo!(int)(); // This causes the error }This is just another example of the property sugar being subpar. With real properties, this would not happen. However, as it is, "actor.world.foo!(int)()" parses as an attempt to access "foo!(int)()" from the _method_ designated by "actor.world", _not_ from the return value of actor.world().
Nov 19 2008
I don't understand why we wouldn't want properties either. Another issue I've had a couple times, although there might be a good reason for this I'm not aware of: class Foo { int x; } void set(inout int x) { x = 10; } void main() { auto foo = new Foo(); set(foo.x); // This works fine } But then if you need to make x a property: class Foo { int _x; int x() { return _x; } int x(int val) { return _x = val; } } You get "Error: foo.x() is not an lvalue"
Nov 19 2008
On Wed, Nov 19, 2008 at 4:59 PM, Brian <digitalmars brianguertin.com> wrote:I don't understand why we wouldn't want properties either. Another issue I've had a couple times, although there might be a good reason for this I'm not aware of: class Foo { int x; } void set(inout int x) { x = 10; } void main() { auto foo = new Foo(); set(foo.x); // This works fine } But then if you need to make x a property: class Foo { int _x; int x() { return _x; } int x(int val) { return _x = val; } } You get "Error: foo.x() is not an lvalue"That one's trickier, even if you did have properties. Even "true" properties would still boil down to a function call. Set expects a reference to an integer. How do you convert getter/setter functions into an integer? It doesn't work now because foo.x is a function, not an int. Also, I wonder if ref returns could help here..
Nov 19 2008
"Jarrett Billingsley" <jarrett.billingsley gmail.com> wrote in message news:mailman.19.1227139335.22690.digitalmars-d puremagic.com...On Wed, Nov 19, 2008 at 4:59 PM, Brian <digitalmars brianguertin.com> wrote:class Foo { int x { get { return x.rawValue; }; set { x.rawValue = newValue; } } } void makeTen(inout int x) { x = 10; } void main() { int i; auto foo = new Foo(); makeTen(i); // Ok // compiler knows that foo.x is an int property // and turns this: makeTen(foo.x); // into this: auto _foo_x = foo.x; makeTen(_foo_x); foo.x = _foo_x; // and finally this: auto _foo_x = foo.x.get(); makeTen(_foo_x); foo.x.set(_foo_x); }I don't understand why we wouldn't want properties either. Another issue I've had a couple times, although there might be a good reason for this I'm not aware of: class Foo { int x; } void set(inout int x) { x = 10; } void main() { auto foo = new Foo(); set(foo.x); // This works fine } But then if you need to make x a property: class Foo { int _x; int x() { return _x; } int x(int val) { return _x = val; } } You get "Error: foo.x() is not an lvalue"That one's trickier, even if you did have properties. Even "true" properties would still boil down to a function call. Set expects a reference to an integer. How do you convert getter/setter functions into an integer?It doesn't work now because foo.x is a function, not an int. Also, I wonder if ref returns could help here..
Nov 25 2008
On Tue, Nov 25, 2008 at 10:44 PM, Nick Sabalausky <a a.a> wrote:// compiler knows that foo.x is an int property // and turns this: makeTen(foo.x); // into this: auto _foo_x = foo.x; makeTen(_foo_x); foo.x = _foo_x; // and finally this: auto _foo_x = foo.x.get(); makeTen(_foo_x); foo.x.set(_foo_x);I considered this, but what if your setter/getter had some kind of side effect? I know, it's probably a little thing to worry about, but still, I would have intuitively expected it to have been evaluated each time the ref parameter was accessed in the function instead of just once before and after the call.
Nov 25 2008
"Jarrett Billingsley" <jarrett.billingsley gmail.com> wrote in message news:mailman.59.1227675354.22690.digitalmars-d puremagic.com...On Tue, Nov 25, 2008 at 10:44 PM, Nick Sabalausky <a a.a> wrote:I thought about that too, but the only realistic examples of that I can think of would involve writing getters/setters that abuse the whole point of property syntax. I'm not completely certain, but I think this might be an issue that's akin to using operator overloading to make '*' peform a subtraction. Can anyone think of any non-abusive case where the above would fail? Maybe something with threads and synchronization? Another idea, but possibly messy: Maybe there could be some automatic behind-the-scenes templatization/overloading such that: If there's a function ("bar") that has a parameter passed by reference ("x"), and you try to pass "bar" a property (of the correct type), then an overloaded version of "bar" is created which replaces accesses to x with calls to x's getter/setter. Ie: void bar(inout int x) { x = x + 2; } void main() { int i; auto foo = new Foo(); bar(i); bar(foo.x); // When the compiler detects the above line, // it generates the following overload of bar: } // Automatically generated by compiler, // unless "bar(foo.x);" above is commented out. void bar(inout property!(int) x) // "property!(T)" is either built-in or part of the core library { x.setter(x.getter() + 2); } Although, I suppose that might still create an excess of extra functions when using dynamically-linked libraries (or maybe not, because it would probably only be needed on inout params, and I don't think it's common to have a large number of those).// compiler knows that foo.x is an int property // and turns this: makeTen(foo.x); // into this: auto _foo_x = foo.x; makeTen(_foo_x); foo.x = _foo_x; // and finally this: auto _foo_x = foo.x.get(); makeTen(_foo_x); foo.x.set(_foo_x);I considered this, but what if your setter/getter had some kind of side effect? I know, it's probably a little thing to worry about, but still, I would have intuitively expected it to have been evaluated each time the ref parameter was accessed in the function instead of just once before and after the call.
Nov 26 2008
On Wed, Nov 26, 2008 at 8:12 AM, Nick Sabalausky <a a.a> wrote:Another idea, but possibly messy: Maybe there could be some automatic behind-the-scenes templatization/overloading such that: If there's a function ("bar") that has a parameter passed by reference ("x"), and you try to pass "bar" a property (of the correct type), then an overloaded version of "bar" is created which replaces accesses to x with calls to x's getter/setter. Ie: void bar(inout int x) { x = x + 2; } void main() { int i; auto foo = new Foo(); bar(i); bar(foo.x); // When the compiler detects the above line, // it generates the following overload of bar: } // Automatically generated by compiler, // unless "bar(foo.x);" above is commented out. void bar(inout property!(int) x) // "property!(T)" is either built-in or part of the core library { x.setter(x.getter() + 2); } Although, I suppose that might still create an excess of extra functions when using dynamically-linked libraries (or maybe not, because it would probably only be needed on inout params, and I don't think it's common to have a large number of those).It would also make it difficult to have virtual methods with ref parameters, since the compiler might have to generate 2 ^ (num ref params) overloads of each such method.
Nov 26 2008
"Jarrett Billingsley" <jarrett.billingsley gmail.com> wrote in message news:mailman.61.1227711020.22690.digitalmars-d puremagic.com...On Wed, Nov 26, 2008 at 8:12 AM, Nick Sabalausky <a a.a> wrote:But how often are "inout" params really used anyway? Plus, unless there's dynamic library loading going on, it would only have to generate the ones that are actually used. I still prefer my original suggestion though. This is just in the case that my original suggestion turns out to have problems that realistically crop up even when not abusing property syntax.Another idea, but possibly messy: Maybe there could be some automatic behind-the-scenes templatization/overloading such that: If there's a function ("bar") that has a parameter passed by reference ("x"), and you try to pass "bar" a property (of the correct type), then an overloaded version of "bar" is created which replaces accesses to x with calls to x's getter/setter. Ie: void bar(inout int x) { x = x + 2; } void main() { int i; auto foo = new Foo(); bar(i); bar(foo.x); // When the compiler detects the above line, // it generates the following overload of bar: } // Automatically generated by compiler, // unless "bar(foo.x);" above is commented out. void bar(inout property!(int) x) // "property!(T)" is either built-in or part of the core library { x.setter(x.getter() + 2); } Although, I suppose that might still create an excess of extra functions when using dynamically-linked libraries (or maybe not, because it would probably only be needed on inout params, and I don't think it's common to have a large number of those).It would also make it difficult to have virtual methods with ref parameters, since the compiler might have to generate 2 ^ (num ref params) overloads of each such method.
Nov 26 2008
On Wed, Nov 26, 2008 at 4:07 PM, Nick Sabalausky <a a.a> wrote:But how often are "inout" params really used anyway?I use them a lot when passing nontrivial structs around.Plus, unless there's dynamic library loading going on, it would only have to generate the ones that are actually used.No; the problem manifests itself whenever separate compilation is used as well, including not only compiling normal programs, but also using statically-linked libraries.
Nov 26 2008
Denis Koroskin wrote:But you are well aware of _other_ cases in which you _have to_ put an extra pair of parens to access some property method/field thus broking an encapsulation and preventing the class designer to replace properties with fields and vice versa at a later stage. It's simply broken! You say that empty pair of parens is equivalent to none of them and thus it is allowed to omit them, but it's not true at all. There are lots of examples where "auto foo = bar();" != "auto foo = bar;" and "auto foo = obj.bar();" != "auto foo = obj.bar;" (delegates, class/struct instances with overloaded opCall, etc). - such a duality is confusing (when may you omit the parens and when you may not?) - it makes the language more complex (rules are so complex that hardly anyone fully understands them) - it leads to code inconsistency (half of the programmers remove an "extra" pair of parens and other half preserve them) - it is a source of many compiler bugs (this and lots of related ones) - it contributes to user code bugs that are hard to find at times ("oops, I missed a pair of parens. God, I thougth that they were optional"). to a recent "Top 5 D problems" poll and now that a Tango/Phobos common I really wish I could understand Walter arguments against proper properties in D...Some good points. -Joel
Nov 19 2008
Denis Koroskin wrote: ...to a recent "Top 5 D problems" poll and now that a Tango/Phobos common... Could I get a link to that one? I think I missed it, and I'm curious. Thanks, - Chad
Nov 20 2008
On Thu, 20 Nov 2008 23:59:03 -0500, Chad J <gamerchad __spam.is.bad__gmail.com> wrote:Denis Koroskin wrote: ...http://www.digitalmars.com/d/archives/digitalmars/D/Top_5_77130.html Gideto a recent "Top 5 D problems" poll and now that a Tango/Phobos common... Could I get a link to that one? I think I missed it, and I'm curious.
Nov 21 2008
On 2008-11-19 12:49:14 -0500, "Denis Koroskin" <2korden gmail.com> said:It's simply broken! You say that empty pair of parens is equivalent to none of them and thus it is allowed to omit them, but it's not true at all. There are lots of examples where "auto foo = bar();" != "auto foo = bar;" and "auto foo = obj.bar();" != "auto foo = obj.bar;" (delegates, class/struct instances with overloaded opCall, etc).As much as I like the no-parens function call syntax, I have to agree with you: it bring inconsistencies.- such a duality is confusing (when may you omit the parens and when you may not?)Where it becomes confusing is where you try to call the return value of a function, or a no-argument function template. While the most common case (simple function call) may be working right, the no-parens function call syntax creates many not-so-rare corner case we have to deal with. Those cases make it confusing.- it makes the language more complex (rules are so complex that hardly anyone fully understands them)I don't think each rule for each callable type is in itself that complex, but mixing them leads to complexity.- it leads to code inconsistency (half of the programmers remove an "extra" pair of parens and other half preserve them)Indeed. I don't think it's bad in itself to have two ways to write something. After all, you can call directly someStruct.opAdd if you prefer that to writing "+". The problem is that in some cases (function pointers, delegates, opCall) it changes the meaning while in other (plain function) it means the same thing. That's inconsistent, it prevents interchangability between those types, and it becomes confusing when using them together.- it is a source of many compiler bugs (this and lots of related ones)I'm not sure having bugs in the compiler is a valid argument against the syntax. Creating a whole new property syntax is bound to have bugs too.- it contributes to user code bugs that are hard to find at times ("oops, I missed a pair of parens. God, I thougth that they were optional").Indeed. So as I said above, I agree that no-parens function calls make the language inconsistant. I still like it because I find it aesthetically pleasing and because it simplifies the concept of properties by making them simple function calls, but at the same time I'm quite annoyed by the inconsistencies. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Nov 21 2008
"Michel Fortin" <michel.fortin michelf.com> wrote in message news:gg6c9q$1p2r$1 digitalmars.com...On 2008-11-19 12:49:14 -0500, "Denis Koroskin" <2korden gmail.com> said:That's why I like the consistency other languages have of: - With parens: Invoke function - Without parens: Refer to function itself Example of preferred syntax: class Beeper { void beep() {...} } void main() { auto beeper = new Beeper(); // Beep beeper.beep(); // Make a beeping delegate auto dgBeep = beeper.beep; // Beep twice later doLater(dgBeep); doLater(beeper.beep); //Error: doLater expects "void delegate(void)", not "void" doLater(beeper.beep()); }It's simply broken! You say that empty pair of parens is equivalent to none of them and thus it is allowed to omit them, but it's not true at all. There are lots of examples where "auto foo = bar();" != "auto foo = bar;" and "auto foo = obj.bar();" != "auto foo = obj.bar;" (delegates, class/struct instances with overloaded opCall, etc).As much as I like the no-parens function call syntax, I have to agree with you: it bring inconsistencies.- such a duality is confusing (when may you omit the parens and when you may not?)Where it becomes confusing is where you try to call the return value of a function, or a no-argument function template. While the most common case (simple function call) may be working right, the no-parens function call syntax creates many not-so-rare corner case we have to deal with. Those cases make it confusing.- it makes the language more complex (rules are so complex that hardly anyone fully understands them)I don't think each rule for each callable type is in itself that complex, but mixing them leads to complexity.- it leads to code inconsistency (half of the programmers remove an "extra" pair of parens and other half preserve them)Indeed. I don't think it's bad in itself to have two ways to write something. After all, you can call directly someStruct.opAdd if you prefer that to writing "+". The problem is that in some cases (function pointers, delegates, opCall) it changes the meaning while in other (plain function) it means the same thing. That's inconsistent, it prevents interchangability between those types, and it becomes confusing when using them together.- it is a source of many compiler bugs (this and lots of related ones)I'm not sure having bugs in the compiler is a valid argument against the syntax. Creating a whole new property syntax is bound to have bugs too.- it contributes to user code bugs that are hard to find at times ("oops, I missed a pair of parens. God, I thougth that they were optional").Indeed. So as I said above, I agree that no-parens function calls make the language inconsistant. I still like it because I find it aesthetically pleasing and because it simplifies the concept of properties by making them simple function calls, but at the same time I'm quite annoyed by the inconsistencies. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Nov 25 2008
Nick SabalauskyThat's why I like the consistency other languages have of: - With parens: Invoke function - Without parens: Refer to function itself Example of preferred syntax: ...I agree, this is better (in Python there's such syntax). (I am hopeful for the future of D because I've seen there are lot of people in this neswgroup that seem to have better ideas :-) ). In alternative, you may also require the & to refer to the function, this makes the syntax more explicit and makes the compiler raise an error if you forget both parens or &: auto x = foo(); // call the callable auto x = &foo; // delegate or function pointer or closure auto x = foo; // syntax error Bye, bearophile
Nov 25 2008
Nick Sabalausky Wrote:That's why I like the consistency other languages have of: - With parens: Invoke function - Without parens: Refer to function itselfIt sounds nice, but then this is what may happen: That's why I have suggested a more explicit syntax, to avoid mistakes, that only adds a char (&): auto x = foo(); // call the callable auto x = &foo; // delegate or function pointer or closure auto x = foo.sizeof; // OK, x becomes 4 or 8, etc. auto x = foo; // syntax error Bye, bearophile
Nov 27 2008
"Andrei Alexandrescu" wroteJarrett Billingsley wrote:Yes, one that would not have existed without the ambiguity that is now present in the syntax. It is one of those things that Walter didn't forsee, but with true property syntax, it (and many other ambiguities) would have been covered. I'm not saying this is proof we should have property syntax, but I'm sure people will continue to find problems due to the inherent ambiguity. -SteveThis is just another example of the property sugar being subpar. With real properties, this would not happen. However, as it is, "actor.world.foo!(int)()" parses as an attempt to access "foo!(int)()" from the _method_ designated by "actor.world", _not_ from the return value of actor.world().I think (in this particular case) it's only about a compiler bug.
Nov 20 2008
Denis Koroskin wrote:a recent "Top 5 D problems" poll and now that a Tango/Phobos common I really wish I could understand Walter arguments against proper properties in D...Something odd happened. I saw a different message from you (longer and a tad more inquisitive), but when I tried to reply, the shorter message above appeared... what happened? Andrei
Nov 19 2008
20.11.08 в 04:29 Andrei Alexandrescu в своём письме писал(а):Denis Koroskin wrote:I guess it's at your side 'cause I didn't edit my message and it is fully accessible from other computers. Here is it via a webnews interface: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=79900 (Did you select a quote and then pressed a reply button? My newsreader pastes the selected quote only to the reply body if anything is selected and the whole message otherwise. I notice this because I have a habit of selecting the sentence as I read it).to a recent "Top 5 D problems" poll and now that a Tango/Phobos I really wish I could understand Walter arguments against proper properties in D...Something odd happened. I saw a different message from you (longer and a tad more inquisitive), but when I tried to reply, the shorter message above appeared... what happened? Andrei
Nov 19 2008