www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Arguments and attributes with the same name

reply bearophile <bearophileHUGS lycos.com> writes:
This is correct D code, but I think it's a bad practice to write code like
this, where method arguments have the same name as instance/static attributes
of the class/struct.

class Foo {
    int x;
    this(int x) { this.x = x; }
    void inc(int x) { this.x += x; }
}
struct Bar {
    static int x;
    void inc(int x) { Bar.x += x; }
}
void main() {}


In Python this problem is less important because the language forces you to
always prepend the argument names with "self.", while in D the "this." is
optional.

In the last years D has added errors for situations where you use duplicated
names, for example in nested scopes or in with statement.

So do you think it's a good idea to forbid/warn against such name clash?

Bye,
bearophile
Mar 04 2010
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
bearophile wrote:
 This is correct D code, but I think it's a bad practice to write code like
this, where method arguments have the same name as instance/static attributes
of the class/struct.
 
 class Foo {
     int x;
     this(int x) { this.x = x; }
     void inc(int x) { this.x += x; }
 }
 struct Bar {
     static int x;
     void inc(int x) { Bar.x += x; }
 }
 void main() {}
 
 
 In Python this problem is less important because the language forces you to
always prepend the argument names with "self.", while in D the "this." is
optional.
 
 In the last years D has added errors for situations where you use duplicated
names, for example in nested scopes or in with statement.
 
 So do you think it's a good idea to forbid/warn against such name clash?
This can be solved if the compiler warns when an assignment is from a variable to the same one. x = x; // error: assignment has no effect
Mar 04 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Ary Borenszweig:

 This can be solved if the compiler warns when an assignment is from a 
 variable to the same one.
 
 x = x; // error: assignment has no effect
That's nice in general to have, but I think it's not enough, because if I want to assign to an attribute an incremented value: x = x+1; What is that x? The attribute or the argument? Bye, bearophile
Mar 04 2010
parent Ary Borenszweig <ary esperanto.org.ar> writes:
bearophile wrote:
 Ary Borenszweig:
 
 This can be solved if the compiler warns when an assignment is from a 
 variable to the same one.

 x = x; // error: assignment has no effect
That's nice in general to have, but I think it's not enough, because if I want to assign to an attribute an incremented value: x = x+1; What is that x? The attribute or the argument?
class Foo: def __init__(self, x): x = x + 1 This compiles just fine in pyhtoh. What is x here? The argument, of course, because that's how it works in python. You forgot to put self before x. class Foo { int x; this(int x) { x = x + 1; } } What is x here? The argument, of course, because that's how it works in python. You forgot to put this before x. How is python safer than D in that sense?
Mar 04 2010
prev sibling next sibling parent reply Bane <branimir.milosavljevic gmail.com> writes:
 This can be solved if the compiler warns when an assignment is from a 
 variable to the same one.
 
 x = x; // error: assignment has no effect
Nice and useful.
Mar 04 2010
parent =?ISO-8859-1?Q?Pelle_M=E5nsson?= <pelle.mansson gmail.com> writes:
On 03/04/2010 02:44 PM, Bane wrote:
 This can be solved if the compiler warns when an assignment is from a
 variable to the same one.

 x = x; // error: assignment has no effect
Nice and useful.
struct A { int i; void opAssign(A a) { i = a.i + 1; } } why not?
Mar 04 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Ary Borenszweig:
 How is python safer than D in that sense?
This is correct D code: class Foo { int x; this() { x = 5; } } void main() {} In Python "self." is always needed to refer to the attribute, and "x" refers to the argument (or a global name, but then you need a global statement). So the eyes of Python programmers are trained to remember such difference. In D the "this." is optional, even in the constructor. So it's more ambiguous, you have to look at the signature of the method you are inside (or the IDE has to color your names differently). Bye, bearophile
Mar 04 2010
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
bearophile wrote:
 Ary Borenszweig:
 How is python safer than D in that sense?
This is correct D code: class Foo { int x; this() { x = 5; } } void main() {} In Python "self." is always needed to refer to the attribute, and "x" refers to the argument (or a global name, but then you need a global statement). So the eyes of Python programmers are trained to remember such difference. In D the "this." is optional, even in the constructor. So it's more ambiguous, you have to look at the signature of the method you are inside (or the IDE has to color your names differently). Bye, bearophile
Now I understand. So you suggest to forbid having an argument name that matches an attribute name? Or require this. for attribute access?
Mar 04 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Ary Borenszweig:
 So you suggest to forbid having an argument name that 
 matches an attribute name? Or require this. for attribute access?
I prefer the compiler to give an error when an argument has the same name of an attribute, it's tidier. If you think that solution is too much restricting, there's a second solution: in only those case, where there can be ambiguity for the eyes of a programmer the compiler can require the use of "this.". Bye, bearophile
Mar 04 2010
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
bearophile wrote:
 Ary Borenszweig:
 So you suggest to forbid having an argument name that 
 matches an attribute name? Or require this. for attribute access?
I prefer the compiler to give an error when an argument has the same name of an attribute, it's tidier.
But python doesn't do it either. Did you suggest the same thing to the python devs? :-)
 
 If you think that solution is too much restricting, there's a second solution:
in only those case, where there can be ambiguity for the eyes of a programmer
the compiler can require the use of "this.".
 
 Bye,
 bearophile
Mar 04 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Ary Borenszweig:

 But python doesn't do it either. Did you suggest the same thing to the 
 python devs? :-)
:-) Well, when I teach Python I give the advice of not using the same names for arguments and attributes. So it's a programming practice. Here the situation in D is worse, because in Python there's always a "self." before attribute names, so there's no real ambiguity. Python is the language I currently prefer, but it's not perfect, and every Python programmer knows it has some messy corners. Even Python programmers recognize that Python can enjoy some of the features D already has, like transitive immutability: http://groups.google.com/group/comp.lang.python/browse_thread/thread/7ef75c20d1be370d/ Or the scope exit: http://groups.google.com/group/comp.lang.python/browse_thread/thread/8c752e871801c223 Or the underscore inside number literals (many people want them, but Hettinger has said that normal Python programs have few literals, and such change requires too much big changes in the Python parser, so they have refused it). I can show you other examples of messy things in Python, like the "confusion" between class instance attributes and class attributes (you can call class attributes even with an instance syntax, with the self). Python was born to write scripts, not to write large multi-programmer applications. Later they have patched some holes, but some of the original more "relaxed" nature of Python shows still (Ruby is worse than Python regarding large multiprogrammer programs). I have just filed the bug: http://d.puremagic.com/issues/show_bug.cgi?id=3878 Bye, bearophile
Mar 04 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 04 Mar 2010 11:06:15 -0500, bearophile <bearophileHUGS lycos.com>  
wrote:

 Ary Borenszweig:

 But python doesn't do it either. Did you suggest the same thing to the
 python devs? :-)
:-) Well, when I teach Python I give the advice of not using the same names for arguments and attributes. So it's a programming practice. Here the situation in D is worse, because in Python there's always a "self." before attribute names, so there's no real ambiguity.
I think the point is, the statement x = x + 1; isn't any more or less ambiguous in D than it is in python. There is a well-defined meaning (and in fact the same meaning). However, your point that it should be more difficult to make such mistakes is a good one. I just don't think it translates at all to "Python's way is better" :) -Steve
Mar 04 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:
 I think the point is, the statement x = x + 1; isn't any more or less  
 ambiguous in D than it is in python.  There is a well-defined meaning (and  
 in fact the same meaning).
It's not the same meaning, this program prints "1": import std.c.stdio: printf; class Foo { int x; this() {} void foo() { x = x + 1; } } void main() { Foo f = new Foo(); f.foo(); printf("%d\n", f.x); // prints 1 } An equivalent Python program with "x = x + 1;" prints: UnboundLocalError: local variable 'x' referenced before assignment Because the usage of "self." is obligatory. Anyway, this whole thread is not about Python, it's about D. Bye, bearophile
Mar 04 2010
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 04 Mar 2010 11:49:13 -0500, bearophile <bearophileHUGS lycos.com>  
wrote:

 Steven Schveighoffer:
 I think the point is, the statement x = x + 1; isn't any more or less
 ambiguous in D than it is in python.  There is a well-defined meaning  
 (and
 in fact the same meaning).
It's not the same meaning, this program prints "1": import std.c.stdio: printf; class Foo { int x; this() {} void foo() { x = x + 1; } } void main() { Foo f = new Foo(); f.foo(); printf("%d\n", f.x); // prints 1 } An equivalent Python program with "x = x + 1;" prints: UnboundLocalError: local variable 'x' referenced before assignment Because the usage of "self." is obligatory.
That's not the ambiguity being discussed. What is being discussed is when there is a local parameter with the same name as an instance field. In that context, (at least from what I read in this thread) D and python are the same. Anyway, it's not important. I agree that it may be good to disallow this from happening in the first place. -Steve
Mar 04 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:hmolpn$1fnv$1 digitalmars.com...
 Python was born to write scripts, not to write large multi-programmer 
 applications. Later they have patched some holes, but some of the original 
 more "relaxed" nature of Python shows still (Ruby is worse than Python 
 regarding large multiprogrammer programs).
As someone who's still somewhat of a novice at ruby, but trying it out a little (b/c it seems to be kind of like a python without indentation-scoping), I'm curious what you see in ruby as being worse for large programs than python. In ruby, I've already been bit by the fact that any explicit "return" from a closure returns from not just the closure itself, but also from the function that called the closure, all the way through the stack, and finally returning from the function that the closure was defined in (unless you remembered to create the closure using the "lambda" keyword). I can imagine a host of problems stemming from that, but not a single useful use-case. I assume you've seen some other large-project drawbacks in ruby besides that?
Mar 05 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
I'm curious what you see in ruby as being worse for large programs than python.<
I know some Python, but I have written only small things in Ruby, so my judgement doesn't have strong roots. From what I have seen Ruby: - Has more syntax freedom, this allows you to create a sublanguage fit for a problem, but also makes Ruby code more variable; - Its syntax is sometimes more handy, like the function parenthesis that can be omitted, the automatic return value, but this also increases the possible bugs a little; - Ruby monkey patching can be done in Python too, but it's considered a bad practice because it's not scoped. This Ruby practice sometimes causes problems. Python looks like a little more tidy and regular language compared to Ruby. I associate this to the ability to write a little larger programs safely. But such difference between Ruby and Python isn't large, they are two similar languages (more than Pascal and C were). It's also a matter of programmer taste, there are people that like a little more freedom (Perl, Ruby, C), and people that like a "safer" language (Java, Ada, and probably Haskell too). D2 is a bit safer than C. In any language you can define a style guide to help you write bigger amounts of code, this is the Google Style Guide for Python: http://google-styleguide.googlecode.com/svn/trunk/pyguide.html Bye, bearophile
Mar 06 2010
prev sibling parent reply Clemens <eriatarka84 gmail.com> writes:
bearophile Wrote:

 Ary Borenszweig:
 So you suggest to forbid having an argument name that 
 matches an attribute name? Or require this. for attribute access?
I prefer the compiler to give an error when an argument has the same name of an attribute, it's tidier.
I'd rather not have that, I like to write my constructors in the way you have shown in your first post: class Foo { int x; this(int x) { this.x = x; } } Saves me from inventing silly names for the parameters (like "theX") or appending ugly pre-/suffixes like an underscore.
 
 If you think that solution is too much restricting, there's a second solution:
in only those case, where there can be ambiguity for the eyes of a programmer
the compiler can require the use of "this.".
I don't understand this suggestion. As soon as you have an instance variable x and a function parameter x, there will *always* be ambiguity (unless you don't use the parameter). Requiring the use of "this." amounts to disallowing access to the parameter x. Or do you suggest making the distinction based on whether x is used as an lvalue or a rvalue?
Mar 04 2010
parent Jonathan M Davis <jmdavisProg gmail.com> writes:
Clemens wrote:

 bearophile Wrote:
 
 Ary Borenszweig:
 So you suggest to forbid having an argument name that
 matches an attribute name? Or require this. for attribute access?
I prefer the compiler to give an error when an argument has the same name of an attribute, it's tidier.
I'd rather not have that, I like to write my constructors in the way you have shown in your first post: class Foo { int x; this(int x) { this.x = x; } } Saves me from inventing silly names for the parameters (like "theX") or appending ugly pre-/suffixes like an underscore.
Agreed. It would be _highly_ annoying if you couldn't have parameters to member functions (constructors or otherwise) which had the same names as member variables. And if you have protected member variables with the same name as a parameter, it would get even worse. Not to mention, properties (which may not be associated with a member variable at all) would likely fall in the same category and it would be even worse. x = x; is clearly an error. No, x = x + 1; is not, but it's not at all ambiguous. If you want to make absolutely certain that you never have this issue, either always use this or use the more common solution of appending your member variable's names with _ or m_, so you'd get _x = x; I really don't think that this is a big problem. And it would be really annoying if you were to restrict parameter names based on the names of member variables or properties. - Jonathan M Davis
Mar 04 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Clemens:
As soon as you have an instance variable x and a function parameter x, there
will *always* be ambiguity (unless you don't use the parameter). Requiring the
use of "this." amounts to disallowing access to the parameter x.<
Thank you for spotting my stupid idea :o) I will update the enhancement request with this note of yours. Bye, bearophile
Mar 04 2010