digitalmars.D - toString ugliness
- Jerry <jlquinn optonline.net> Dec 06 2008
- "Jarrett Billingsley" <jarrett.billingsley gmail.com> Dec 06 2008
- Jerry <jlquinn optonline.net> Dec 06 2008
- Ary Borenszweig <ary esperanto.org.ar> Dec 07 2008
- Ary Borenszweig <ary esperanto.org.ar> Dec 07 2008
- Christopher Wright <dhasenan gmail.com> Dec 07 2008
- "Nick Sabalausky" <a a.a> Dec 07 2008
- bearophile <bearophileHUGS lycos.com> Dec 07 2008
- Sergey Gromov <snake.scaly gmail.com> Dec 07 2008
- Christopher Wright <dhasenan gmail.com> Dec 07 2008
- "Jarrett Billingsley" <jarrett.billingsley gmail.com> Dec 06 2008
- "Jarrett Billingsley" <jarrett.billingsley gmail.com> Dec 06 2008
- Steve Schveighoffer <schveiguy yahoo.com> Dec 06 2008
- Ary Borenszweig <ary esperanto.org.ar> Dec 07 2008
- bearophile <bearophileHUGS lycos.com> Dec 07 2008
- "Jarrett Billingsley" <jarrett.billingsley gmail.com> Dec 07 2008
- "Jarrett Billingsley" <jarrett.billingsley gmail.com> Dec 07 2008
toString() doesn't work inside a class member function.
import std.string;
class A {
void f() {
string s = toString(5);
}
}
This errors with junk.d(19): function object.Object.toString () does not match
parameter types (int)
This is a nuisance and a wart (though not a bug per-se).
If the language really can't handle distinguishing this.toString() from
toString(int), then std.string.toString really should have a different name.
It can be solved somewhat by documenting clearly that to!(string)(int)
be used instead, which seems silly to me. I'm irritated by the 3 extra chars
required to type a to!(type) template.
.toString() works around the problem, but why should it be needed? This is
unfortunate.
Does this bother anyone else? If not, I'll return to my lurking cave :-)
Dec 06 2008
On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name. It can be solved somewhat by documenting clearly that to!(string)(int) be used instead, which seems silly to me. I'm irritated by the 3 extra chars required to type a to!(type) template. .toString() works around the problem, but why should it be needed? This is unfortunate. Does this bother anyone else? If not, I'll return to my lurking cave :-)
It's annoying but it's not enough to make me want to change anything. ;)
Dec 06 2008
Jarrett Billingsley Wrote:On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name.
As I'm thinking about this, why does this actually fail? The parameter doesn't match the prototype for this.toString(), so why not match against the global function? Is this due to the behavior that override solves? Would marking Object.toString() as override fix the problem?
Dec 06 2008
Jarrett Billingsley escribió:On Sat, Dec 6, 2008 at 12:11 PM, Jerry <jlquinn optonline.net> wrote:Jarrett Billingsley Wrote:On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name.
Is this due to the behavior that override solves? Would marking Object.toString() as override fix the problem?
As far as I know, it's because D does not use ADL (argument-dependent lookup). That is, it simply looks for the toString that is in the nearest enclosing scope, and if it doesn't match - too bad. Compare this behavior to C++, where it would then continue on, looking for a definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
But the overloading is obvious! It looks for toString(...) and it founds it in the class, but the overloading is wrong. So for me, it should keep looking in the enclosing scopes.
Dec 07 2008
Jarrett Billingsley escribió:On Sun, Dec 7, 2008 at 7:12 AM, Ary Borenszweig <ary esperanto.org.ar> wrote:definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
in the class, but the overloading is wrong. So for me, it should keep looking in the enclosing scopes.
That's why I said "*most* of the time" ;) I'll agree that it's a bit counterintuitive, but I'd rather have the compiler be a little stupid in this regard than to pay the price of unexpected function matches for a little bit of convenience.
Ah, I see. Well, I'd like to see such an example then. :-P
Dec 07 2008
Ary Borenszweig wrote:Jarrett Billingsley escribió:On Sun, Dec 7, 2008 at 7:12 AM, Ary Borenszweig <ary esperanto.org.ar> wrote:definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
founds it in the class, but the overloading is wrong. So for me, it should keep looking in the enclosing scopes.
That's why I said "*most* of the time" ;) I'll agree that it's a bit counterintuitive, but I'd rather have the compiler be a little stupid in this regard than to pay the price of unexpected function matches for a little bit of convenience.
Ah, I see. Well, I'd like to see such an example then. :-P
It usually won't be an issue, I think. You'll give your functions descriptive names, and you won't have overloads in different scopes that take similar arguments. So any example I give will probably seem contrived. I certainly have only encountered this compiler error a bare handful of times, and only with toString. That said, errors of this kind would be difficult to track down, and the workaround is very simple once you know it -- and not that difficult to come up with if you don't. I think I came up using .toString without having anyone tell me about it, and if I hadn't, I would have used the fully qualified name (or an alias).
Dec 07 2008
"Christopher Wright" <dhasenan gmail.com> wrote in message news:ghhbn3$2u32$1 digitalmars.com...Ary Borenszweig wrote:Jarrett Billingsley escribió:On Sun, Dec 7, 2008 at 7:12 AM, Ary Borenszweig <ary esperanto.org.ar> wrote:definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
founds it in the class, but the overloading is wrong. So for me, it should keep looking in the enclosing scopes.
That's why I said "*most* of the time" ;) I'll agree that it's a bit counterintuitive, but I'd rather have the compiler be a little stupid in this regard than to pay the price of unexpected function matches for a little bit of convenience.
Ah, I see. Well, I'd like to see such an example then. :-P
It usually won't be an issue, I think. You'll give your functions descriptive names, and you won't have overloads in different scopes that take similar arguments. So any example I give will probably seem contrived. I certainly have only encountered this compiler error a bare handful of times, and only with toString. That said, errors of this kind would be difficult to track down, and the workaround is very simple once you know it -- and not that difficult to come up with if you don't. I think I came up using .toString without having anyone tell me about it, and if I hadn't, I would have used the fully qualified name (or an alias).
I kind of like Ruby's requirement that accessing "this.whatever" *must* be done like " whatever" (with the "this." part not being needed). Omitting the means you're talking about either a local identifier or a global one. I don't know if that stuff applies to member functions as well or if it's just member vars, but if it did apply to member funcs then that would certainly solve the "finding the correct toString" issue. Of course, that would probably be way too big of a syntax change for D, though.
Dec 07 2008
Nick Sabalausky:I kind of like Ruby's requirement that accessing "this.whatever" *must* be done like " whatever" (with the "this." part not being needed). Omitting the means you're talking about either a local identifier or a global one. I don't know if that stuff applies to member functions as well or if it's just member vars, but if it did apply to member funcs then that would certainly solve the "finding the correct toString" issue. Of course, that would probably be way too big of a syntax change for D, though.
In Ruby you also use for class variables (similar to static attributes of classes in D). I have often seen C++ code where the name of instance attributes are prefixed by "m_". In D now and then I use "this.somename" to avoid name clashes (for example with argument variables) or to make more explicit that a variable isn't local. Using a default prefix, like or $ to instance attributes in D2 code will make such code look a little ugly, but probably also more explicit too. (It's also short, shorter than "m_" and shorter than "this."). So I may end liking this syntax change. Bye, bearophile
Dec 07 2008
Sat, 6 Dec 2008 13:04:56 -0500, Jarrett Billingsley wrote:On Sat, Dec 6, 2008 at 12:11 PM, Jerry <jlquinn optonline.net> wrote:Jarrett Billingsley Wrote:On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name.
As I'm thinking about this, why does this actually fail? The parameter doesn't match the prototype for this.toString(), so why not match against the global function? Is this due to the behavior that override solves? Would marking Object.toString() as override fix the problem?
As far as I know, it's because D does not use ADL (argument-dependent lookup). That is, it simply looks for the toString that is in the nearest enclosing scope, and if it doesn't match - too bad. Compare this behavior to C++, where it would then continue on, looking for a definition of toString that does match.
Not correct. C++ uses the same rules to build overload sets as D. That is, a function declaration in an inner scope hides any function declarations with the same name in outer scopes. I /think/ there should be a good rationale behind this design. Actually, any declaration works like this. A variable declaration hides any declarations with the same name in the outer scopes. Probably functions follow this rule to make overloading more predictable.
Dec 07 2008
Sergey Gromov wrote:Not correct. C++ uses the same rules to build overload sets as D. That is, a function declaration in an inner scope hides any function declarations with the same name in outer scopes. I /think/ there should be a good rationale behind this design.
I've been using C++ lately, and I'd put it a bit differently: I think there /should/ be a good rationale behind its design.
Dec 07 2008
On Sat, Dec 6, 2008 at 12:11 PM, Jerry <jlquinn optonline.net> wrote:Jarrett Billingsley Wrote:On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name.
As I'm thinking about this, why does this actually fail? The parameter doesn't match the prototype for this.toString(), so why not match against the global function? Is this due to the behavior that override solves? Would marking Object.toString() as override fix the problem?
As far as I know, it's because D does not use ADL (argument-dependent lookup). That is, it simply looks for the toString that is in the nearest enclosing scope, and if it doesn't match - too bad. Compare this behavior to C++, where it would then continue on, looking for a definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
Dec 06 2008
On Sat, Dec 6, 2008 at 12:11 PM, Jerry <jlquinn optonline.net> wrote:Jarrett Billingsley Wrote:On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name.
As I'm thinking about this, why does this actually fail? The parameter doesn't match the prototype for this.toString(), so why not match against the global function? Is this due to the behavior that override solves? Would marking Object.toString() as override fix the problem?
As far as I know, it's because D does not use ADL (argument-dependent lookup). That is, it simply looks for the toString that is in the nearest enclosing scope, and if it doesn't match - too bad. Compare this behavior to C++, where it would then continue on, looking for a definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
Dec 06 2008
On Sat, 06 Dec 2008 11:21:11 -0500, Jerry wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name. It can be solved somewhat by documenting clearly that to!(string)(int) be used instead, which seems silly to me. I'm irritated by the 3 extra chars required to type a to!(type) template. .toString() works around the problem, but why should it be needed? This is unfortunate. Does this bother anyone else? If not, I'll return to my lurking cave :-)
Doesn't bother me at all. Using tango, I usually rename the appropriate toString module imports. i.e.: import Int = tango.text.convert.Integer; Int.toString(5); But you'd probably hate that. That's *4* more characters! Or you could alias it at the top of the module you want to use it in. alias toString toStr; The object.toString function is so well known, and so intuitive, I doubt there would be any possible way it would be changed. Nor would I want that to change. -Steve
Dec 06 2008
Jerry escribió:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name. It can be solved somewhat by documenting clearly that to!(string)(int) be used instead, which seems silly to me. I'm irritated by the 3 extra chars required to type a to!(type) template. .toString() works around the problem, but why should it be needed? This is unfortunate. Does this bother anyone else? If not, I'll return to my lurking cave :-)
It bothers me. Maybe it doesn't bother anyone else in this newsgroup because they already fell in that trap and they know the solution or the workarounds. For me, there shouldn't be a workaround, it should just work. If I, a human, can understand that toString(int) can't never, EVER, be confused with toString(), why can't the compiler see the same?
Dec 07 2008
Ary Borenszweig:It bothers me. Maybe it doesn't bother anyone else in this newsgroup because they already fell in that trap and they know the solution or the workarounds.
I too have fallen in this little trap, but after the first time you learn to add a "." before toString. I use str()/repr() functions from my dlibs to avoid name clashes with toString() (see below), so I think that it may be better for the method and the global function to have different names. Python avoids such problem because the function and the method have different names: the global built-in functions are named str() and repr() and the methods are __str__() and __repr__(). (each function calls the relative method. If __str__ is absent, __repr__ is called as fallback). str() gives a human-readable textual representation of something, and repr() gives a string representation that whenever possible is the text you have to write to define that thing in the code, so generally eval(repr(x)) == x. Bye, bearophile
Dec 07 2008
On Sun, Dec 7, 2008 at 7:12 AM, Ary Borenszweig <ary esperanto.org.ar> wrote:definition of toString that does match. Most of the time ADL leads to confusing behavior, which is why it was dropped in D.
But the overloading is obvious! It looks for toString(...) and it founds it in the class, but the overloading is wrong. So for me, it should keep looking in the enclosing scopes.
That's why I said "*most* of the time" ;) I'll agree that it's a bit counterintuitive, but I'd rather have the compiler be a little stupid in this regard than to pay the price of unexpected function matches for a little bit of convenience.
Dec 07 2008
On Sun, Dec 7, 2008 at 5:54 PM, Sergey Gromov <snake.scaly gmail.com> wrote:Sat, 6 Dec 2008 13:04:56 -0500, Jarrett Billingsley wrote:On Sat, Dec 6, 2008 at 12:11 PM, Jerry <jlquinn optonline.net> wrote:Jarrett Billingsley Wrote:On Sat, Dec 6, 2008 at 11:21 AM, Jerry <jlquinn optonline.net> wrote:toString() doesn't work inside a class member function. import std.string; class A { void f() { string s = toString(5); } } This errors with junk.d(19): function object.Object.toString () does not match parameter types (int) This is a nuisance and a wart (though not a bug per-se). If the language really can't handle distinguishing this.toString() from toString(int), then std.string.toString really should have a different name.
As I'm thinking about this, why does this actually fail? The parameter doesn't match the prototype for this.toString(), so why not match against the global function? Is this due to the behavior that override solves? Would marking Object.toString() as override fix the problem?
As far as I know, it's because D does not use ADL (argument-dependent lookup). That is, it simply looks for the toString that is in the nearest enclosing scope, and if it doesn't match - too bad. Compare this behavior to C++, where it would then continue on, looking for a definition of toString that does match.
Not correct. C++ uses the same rules to build overload sets as D. That is, a function declaration in an inner scope hides any function declarations with the same name in outer scopes. I /think/ there should be a good rationale behind this design. Actually, any declaration works like this. A variable declaration hides any declarations with the same name in the outer scopes. Probably functions follow this rule to make overloading more predictable.
Sorry.
Dec 07 2008









bearophile <bearophileHUGS lycos.com> 