www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Properties

reply Vishaal <vishaal nospam.com> writes:
Properties, such as array.length, should return lvalues to allow:
a.length += 8;
or other similar statements.
Jan 07 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Vishaal,

 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
Jan 07 2009
next sibling parent Moritz Warning <moritzwarning web.de> writes:
On Thu, 08 Jan 2009 00:49:38 +0000, BCS wrote:

 Reply to Vishaal,
 
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
http://d.puremagic.com/issues/show_bug.cgi?id=808 *gripes*
Jan 07 2009
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from BCS (ao pathlink.com)'s article
 Reply to Vishaal,
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
Yeah, this has been mentioned in the past before. The most obvious way to make it work w/o any breaking or significantly bulk-adding changes would be to define foo.length += 8 to mean foo = foo.length() + 8, or foo.length++ mean foo = foo.length + 1. This would be pure syntactic sugar, as it is when working with primitives. One problem that comes to mind is if, instead of length, which is presumably some kind of integer, you have a property for some user defined type with operator overloading. This user-defined type could define opAdd to do something arbitrarily different from opAddAssign. Even if we assume that no reasonable programmer would do this and treat this as a "who cares?" corner case, there's still the problem of opInc and opAddAssign being much cheaper in some cases than opAdd. For example, in some cases opAdd might require copying of a whole bunch of stuff, where opInc or opAddAssign just increments a single primitive under the hood. Bottom line is, unless we assume that properties of user-defined types aren't important, we need a better solution. Oh yeah, and on the more special case of arrays, which the compiler already treats as special, yes, foo.length += 2 should be legal. As far as I can tell, this is a no-brainer.
Jan 07 2009
next sibling parent Vishaal <vishaal nospam.com> writes:
dsimcha Wrote:

 == Quote from BCS (ao pathlink.com)'s article
 Reply to Vishaal,
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
Yeah, this has been mentioned in the past before. The most obvious way to make it work w/o any breaking or significantly bulk-adding changes would be to define foo.length += 8 to mean foo = foo.length() + 8, or foo.length++ mean foo = foo.length + 1. This would be pure syntactic sugar, as it is when working with primitives. One problem that comes to mind is if, instead of length, which is presumably some kind of integer, you have a property for some user defined type with operator overloading. This user-defined type could define opAdd to do something arbitrarily different from opAddAssign. Even if we assume that no reasonable programmer would do this and treat this as a "who cares?" corner case, there's still the problem of opInc and opAddAssign being much cheaper in some cases than opAdd. For example, in some cases opAdd might require copying of a whole bunch of stuff, where opInc or opAddAssign just increments a single primitive under the hood. Bottom line is, unless we assume that properties of user-defined types aren't important, we need a better solution. Oh yeah, and on the more special case of arrays, which the compiler already treats as special, yes, foo.length += 2 should be legal. As far as I can tell, this is a no-brainer.
The two methods aren't mutually exclusive. We could let users write opAddAssign if they want but if there would be no benefit (or if they don't care about memory) they wouldn't have to write an opAddAssign and the compiler would expand it. ++gripes.length; Sorry, gripes.length = gripes.length + 1;
Jan 07 2009
prev sibling next sibling parent reply Michiel Helvensteijn <nomail please.com> writes:
dsimcha wrote:

 Yeah, this has been mentioned in the past before.  The most obvious way to
 make it work w/o any breaking or significantly bulk-adding changes would
 be to define foo.length += 8 to mean foo = foo.length() + 8, or
 foo.length++ mean foo =
 foo.length + 1.  This would be pure syntactic sugar, as it is when working
 with primitives.
 
 One problem that comes to mind is if, instead of length, which is
 presumably some kind of integer, you have a property for some user defined
 type with operator
 overloading.  This user-defined type could define opAdd to do something
 arbitrarily different from opAddAssign.  Even if we assume that no
 reasonable programmer would do this and treat this as a "who cares?"
 corner case, there's still the problem of opInc and opAddAssign being much
 cheaper in some cases than
 opAdd.  For example, in some cases opAdd might require copying of a whole
 bunch of stuff, where opInc or opAddAssign just increments a single
 primitive under the hood.
I've always thought properties should work somewhat like this: property int length { get() { return this.len; } set(newLen) { this.len = newLen; } } The return-type of get is automatically int, as is the parameter-type of set. These two functions are automatically called when the property is used. int a = length; // int a = length.get(); length = 10; // length.set(10); In cases where read/write access is needed, the compiler can do this: length++; // int temp = length.get(); // temp++; // length.set(temp); This can work for any user-defined type, since we're using the same operator. If you want it done faster 'under the hood', you can use operator-overloads inside the property: property int length { get() { return this.len; } set(newLen) { this.len = newLen; } void opIncrement() { this.len++; } } -- Michiel
Jan 08 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Michiel Helvensteijn" <nomail please.com> wrote in message 
news:gk4oi2$14tv$1 digitalmars.com...
 dsimcha wrote:

 Yeah, this has been mentioned in the past before.  The most obvious way 
 to
 make it work w/o any breaking or significantly bulk-adding changes would
 be to define foo.length += 8 to mean foo = foo.length() + 8, or
 foo.length++ mean foo =
 foo.length + 1.  This would be pure syntactic sugar, as it is when 
 working
 with primitives.

 One problem that comes to mind is if, instead of length, which is
 presumably some kind of integer, you have a property for some user 
 defined
 type with operator
 overloading.  This user-defined type could define opAdd to do something
 arbitrarily different from opAddAssign.  Even if we assume that no
 reasonable programmer would do this and treat this as a "who cares?"
 corner case, there's still the problem of opInc and opAddAssign being 
 much
 cheaper in some cases than
 opAdd.  For example, in some cases opAdd might require copying of a whole
 bunch of stuff, where opInc or opAddAssign just increments a single
 primitive under the hood.
I've always thought properties should work somewhat like this: property int length { get() { return this.len; } set(newLen) { this.len = newLen; } } The return-type of get is automatically int, as is the parameter-type of set. These two functions are automatically called when the property is used. int a = length; // int a = length.get(); length = 10; // length.set(10); In cases where read/write access is needed, the compiler can do this: length++; // int temp = length.get(); // temp++; // length.set(temp); This can work for any user-defined type, since we're using the same operator. If you want it done faster 'under the hood', you can use operator-overloads inside the property: property int length { get() { return this.len; } set(newLen) { this.len = newLen; } void opIncrement() { this.len++; } }
Agreed. The current way is just sloppy and it bothers me constantly. *gripe* *gripe* *gripe* I would make two modifications to your suggestion though: "get". They're always going to be the same. In the case of "set", it's always going to be just the one param, and it'll be the new value, so just make a special predefined var. Something like: get { return this.len; } that 2. You shouldn't have to manually define a private var to go along with the property. In languages with real properties, the following idiom is used constantly: private int _var; public property int var { get { return _var; } set { _var = $; } void opIncrement() { _var++; } } Why should that be needed? It should be like this: public property int var { // int internalValue; // Automatically created (but named better) get { return internalValue; } set { internalValue = $; } void opIncrement() { internalValue++; } } In the minority of cases where a property doesn't need this variable, "internalValue" can just be optimized away.
Jan 08 2009
parent reply Michiel Helvensteijn <nomail please.com> writes:
Nick Sabalausky wrote:


 "get". They're always going to be the same. In the case of "set", it's
 always going to be just the one param, and it'll be the new value, so just
 make a special predefined var. Something like:
 
 get { return this.len; }

 like that
I have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number. set has a parameter, and the programmer should be able to name it. Also, removing the parentheses would be confusing. I believe it might be better to make them look like this, even: property int length { auto get() { .. } void set(auto name) { .. } } So they would clearly be function declarations.
 2. You shouldn't have to manually define a private var to go along with
 the property. In languages with real properties, the following idiom is
 used constantly:
 
 private int _var;
 public property int var {
    get { return _var; }
    set { _var = $; }
    void opIncrement() { _var++; }
 }
 
 Why should that be needed? It should be like this:
 
 public property int var {
    // int internalValue; // Automatically created (but named better)
    get { return internalValue; }
    set { internalValue = $; }
    void opIncrement() { internalValue++; }
 }
 
 In the minority of cases where a property doesn't need this variable,
 "internalValue" can just be optimized away.
If you really want that behavior, you should just use a public variable. Even changing it to a real property later would not matter for the public interface. -- Michiel
Jan 08 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Michiel Helvensteijn wrote:
 Nick Sabalausky wrote:
 

 "get". They're always going to be the same. In the case of "set", it's
 always going to be just the one param, and it'll be the new value, so just
 make a special predefined var. Something like:

 get { return this.len; }

 like that
I have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number. set has a parameter, and the programmer should be able to name it.
It's very different. A setter has a very specific meaning: set some value. That's why it's called "value". Another name could be the name of the property ("len") or something like "newLen". Which other name would you use? A general function can have any kind of meaning, and so its parameters, and that's why it's ok to have names for them.
 
 Also, removing the parentheses would be confusing.
I believe it might be
 better to make them look like this, even:
 
 property int length {
     auto get() { .. }
     void set(auto name) { .. }
name? But it's the length. :-P
Jan 08 2009
parent reply Michiel Helvensteijn <nomail please.com> writes:
Ary Borenszweig wrote:

 get { return this.len; }

 like that
I have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number. set has a parameter, and the programmer should be able to name it.
It's very different. A setter has a very specific meaning: set some value. That's why it's called "value". Another name could be the name of the property ("len") or something like "newLen". Which other name would you use?
It's not for me to say. It should be up to the programmer. You've already shown that there are at least three possibilities. -- Michiel
Jan 08 2009
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Michiel Helvensteijn wrote:
 Ary Borenszweig wrote:
 
 get { return this.len; }

 like that
I have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number. set has a parameter, and the programmer should be able to name it.
It's very different. A setter has a very specific meaning: set some value. That's why it's called "value". Another name could be the name of the property ("len") or something like "newLen". Which other name would you use?
It's not for me to say. It should be up to the programmer. You've already shown that there are at least three possibilities.
Yes, three. And that's it. That was my point. And they all have pretty much the same meaning. Well, unless you want to name it "nuevaLen", "novaLen", "nouvelleLen", etc. :-P
Jan 08 2009
parent reply Michiel Helvensteijn <nomail please.com> writes:
Ary Borenszweig wrote:

 It's very different. A setter has a very specific meaning: set some
 value. That's why it's called "value". Another name could be the name of
 the property ("len") or something like "newLen". Which other name would
 you use?
It's not for me to say. It should be up to the programmer. You've already shown that there are at least three possibilities.
Yes, three. And that's it. That was my point. And they all have pretty much the same meaning. Well, unless you want to name it "nuevaLen", "novaLen", "nouvelleLen", etc. :-P
Perhaps the implicit declaration "value" (or whatever *you* would call it) inadvertently overshadows a member variable with that name. That could result in a bug that would be pretty hard to find. -- Michiel
Jan 08 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Michiel Helvensteijn" <nomail please.com> wrote in message 
news:gk5f80$2lav$1 digitalmars.com...
 Ary Borenszweig wrote:

 It's very different. A setter has a very specific meaning: set some
 value. That's why it's called "value". Another name could be the name 
 of
 the property ("len") or something like "newLen". Which other name would
 you use?
It's not for me to say. It should be up to the programmer. You've already shown that there are at least three possibilities.
Yes, three. And that's it. That was my point. And they all have pretty much the same meaning. Well, unless you want to name it "nuevaLen", "novaLen", "nouvelleLen", etc. :-P
Perhaps the implicit declaration "value" (or whatever *you* would call it) inadvertently overshadows a member variable with that name. That could result in a bug that would be pretty hard to find.
Overshadowing is already a potential issue anyway, with or without properties. Even a user-defined name could still accidentally overshadow something. Also, using "$" could help minimize overshadowing, the only thing that could ever clash with that is the "array.length" shorthand inside array slices/indexes (and even that already has potential for clashing, specifically when using nested indexes).
Jan 08 2009
parent reply Michiel Helvensteijn <nomail please.com> writes:
Nick Sabalausky wrote:

 Perhaps the implicit declaration "value" (or whatever *you* would call
 it) inadvertently overshadows a member variable with that name. That
 could result in a bug that would be pretty hard to find.
Overshadowing is already a potential issue anyway, with or without properties. Even a user-defined name could still accidentally overshadow something.
Sure, but in that case both of the declarations are explicit. Now there's an invisible variable blocking a visible one. Could be quite confusing.
 Also, using "$" could help minimize overshadowing, the only 
 thing that could ever clash with that is the "array.length" shorthand
 inside array slices/indexes (and even that already has potential for
 clashing, specifically when using nested indexes).
Using $ just doesn't make much sense. To what lengths are you willing to go to avoid typing a few more characters? Or do you really find $ more readable? Who could guess that $ inside the set function stands for its invisible parameter? -- Michiel
Jan 08 2009
parent "Nick Sabalausky" <a a.a> writes:
"Michiel Helvensteijn" <nomail please.com> wrote in message 
news:gk5h9r$2p7g$1 digitalmars.com...
 Nick Sabalausky wrote:

 Perhaps the implicit declaration "value" (or whatever *you* would call
 it) inadvertently overshadows a member variable with that name. That
 could result in a bug that would be pretty hard to find.
Overshadowing is already a potential issue anyway, with or without properties. Even a user-defined name could still accidentally overshadow something.
Sure, but in that case both of the declarations are explicit. Now there's an invisible variable blocking a visible one. Could be quite confusing.
like a keyword than my purely tentative "newValue").
 Also, using "$" could help minimize overshadowing, the only
 thing that could ever clash with that is the "array.length" shorthand
 inside array slices/indexes (and even that already has potential for
 clashing, specifically when using nested indexes).
Using $ just doesn't make much sense. To what lengths are you willing to go to avoid typing a few more characters? Or do you really find $ more readable? Who could guess that $ inside the set function stands for its invisible parameter?
It's not so much about saving typing as the clarity that comes from consistency. And as with "array[0..$]", or the "a + b" stuff in phobos2's functional-style modules, it's easy if you're aware of it (you can't expect every new language feature to be obvious at a glance to someone who's never glanced at the docs). I'll grant that "$" may not be as descriptive as, say "newValue", but I'd certainly find it much more readable than having it named something completely different in every setter in the codebase.
Jan 08 2009
prev sibling next sibling parent reply Chad J <gamerchad __spam.is.bad__gmail.com> writes:
Michiel Helvensteijn wrote:
 Nick Sabalausky wrote:
 
 2. You shouldn't have to manually define a private var to go along with
 the property. In languages with real properties, the following idiom is
 used constantly:

 private int _var;
 public property int var {
    get { return _var; }
    set { _var = $; }
    void opIncrement() { _var++; }
 }

 Why should that be needed? It should be like this:

 public property int var {
    // int internalValue; // Automatically created (but named better)
    get { return internalValue; }
    set { internalValue = $; }
    void opIncrement() { internalValue++; }
 }

 In the minority of cases where a property doesn't need this variable,
 "internalValue" can just be optimized away.
If you really want that behavior, you should just use a public variable. Even changing it to a real property later would not matter for the public interface.
That's not quite why it was suggested. I actually like the idea. It is true that a public member would be preferred in the trivial case. In the general case though, people will have some internal value they are working with and whenever someone works with it they want side effects to happen. Here's an example: int nTimesVarRead = 0; public property int var { get { nTimesVarRead++; return internalValue; } set { internalValue = $; } } compare against: int nTimesVarRead = 0; int m_var; // Annoying extra declaration that is common practice. public property int var { get { nTimesVarRead++; return m_var; } set { m_var = $; } } Thus I rather like that idea. Perhaps, since the compiler knows the name of the property, the name of the generated internal value could just be the name of the property: public property int var { get { return var; } set { var = $; } } public property int foo { get { return foo; } set { foo = $; } } etc.
Jan 08 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Chad J:
 public property int var
 {
     get { return var; }
     set { var = $; }
 }
 
 public property int foo
 {
     get { return foo; }
     set { foo = $; }
 }
I think I have suggested something similar, time ago. The default situations you have shown may enjoy an even shorter syntax, for example: public property int var { get set } That can also become the following when you want only a getter or setter: public property int var { get } Or: public property int var { set } (I don't like all those repeated "foo"/"var", it's not much DRY. But at the moment I see no better solution, that works well for nested classes/structs too). Let's see if Walter likes all this. Bye, bearophile
Jan 08 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:gk5grh$2o8i$1 digitalmars.com...
 Chad J:
 public property int var
 {
     get { return var; }
     set { var = $; }
 }

 public property int foo
 {
     get { return foo; }
     set { foo = $; }
 }
I think I have suggested something similar, time ago. The default situations you have shown may enjoy an even shorter syntax, for example: public property int var { get set } That can also become the following when you want only a getter or setter: public property int var { get } Or: public property int var { set } (I don't like all those repeated "foo"/"var", it's not much DRY. But at the moment I see no better solution, that works well for nested classes/structs too).
Something like this: public property int var { get { return property; } set { property = $; } } Or something like this: public property int foo { get { return $; } set { $ = $new; } }
 Let's see if Walter likes all this.

 Bye,
 bearophile 
Jan 08 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Nick Sabalausky wrote:
 "bearophile"<bearophileHUGS lycos.com>  wrote in message
 news:gk5grh$2o8i$1 digitalmars.com...
 Chad J:
 public property int var
 {
      get { return var; }
      set { var = $; }
 }

 public property int foo
 {
      get { return foo; }
      set { foo = $; }
 }
I think I have suggested something similar, time ago. The default situations you have shown may enjoy an even shorter syntax, for example: public property int var { get set } That can also become the following when you want only a getter or setter: public property int var { get } Or: public property int var { set } (I don't like all those repeated "foo"/"var", it's not much DRY. But at the moment I see no better solution, that works well for nested classes/structs too).
Something like this: public property int var { get { return property; } set { property = $; } } Or something like this: public property int foo { get { return $; } set { $ = $new; } }
 Let's see if Walter likes all this.

 Bye,
 bearophile
I like the general idea, but why invent new words? how about this: public property int var { get { return this; } set { this = new; } } there's one issue with the above - what about the "this" of the container class/struct, but that's solved easily with "outer" just like in nested classes. it makes sense to me since the feature seems to be mainly syntax sugar for something like the following: class A { struct Prop { int internal; int opCall() { return internal; } void opAssign(int value) { internal = value; } } public Prop prop; ... } void main() { auto a = new A; int num = a.prop; a.prop = 9; ... }
Jan 08 2009
parent "Nick Sabalausky" <a a.a> writes:
"Yigal Chripun" <yigal100 gmail.com> wrote in message 
news:gk5t92$fu2$1 digitalmars.com...
 Nick Sabalausky wrote:
 "bearophile"<bearophileHUGS lycos.com>  wrote in message
 news:gk5grh$2o8i$1 digitalmars.com...
 Chad J:
 public property int var
 {
      get { return var; }
      set { var = $; }
 }

 public property int foo
 {
      get { return foo; }
      set { foo = $; }
 }
I think I have suggested something similar, time ago. The default situations you have shown may enjoy an even shorter syntax, for example: public property int var { get set } That can also become the following when you want only a getter or setter: public property int var { get } Or: public property int var { set } (I don't like all those repeated "foo"/"var", it's not much DRY. But at the moment I see no better solution, that works well for nested classes/structs too).
Something like this: public property int var { get { return property; } set { property = $; } } Or something like this: public property int foo { get { return $; } set { $ = $new; } }
 Let's see if Walter likes all this.

 Bye,
 bearophile
I like the general idea, but why invent new words? how about this: public property int var { get { return this; } set { this = new; } } there's one issue with the above - what about the "this" of the container class/struct, but that's solved easily with "outer" just like in nested classes.
*smacks forehead* I completely forget about "outer". That's the only reason I didn't suggest "this". That is good. But using "new" in that particular way bothers me a little. What about making the new value a property of "this": set { this = this.new; } set { this = this.next; } set { this = this.prime; } // Math-style set { this = this.pending; } set { this = this.hcwgcwFNbchbSCCGUgucG; }
 it makes sense to me since the feature seems to be mainly syntax sugar for 
 something like the following:

 class A {
 struct Prop {
 int internal;
 int opCall() { return internal; }
 void opAssign(int value) { internal = value; }
 }
 public Prop prop;
 ...
 }

 void main() {
 auto a = new A;
 int num = a.prop;
 a.prop = 9;
 ...
 }
Good point.
Jan 08 2009
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Chad J" <gamerchad __spam.is.bad__gmail.com> wrote in message 
news:gk5fch$2ldo$1 digitalmars.com...
 Michiel Helvensteijn wrote:
 Nick Sabalausky wrote:

 2. You shouldn't have to manually define a private var to go along with
 the property. In languages with real properties, the following idiom is
 used constantly:

 private int _var;
 public property int var {
    get { return _var; }
    set { _var = $; }
    void opIncrement() { _var++; }
 }

 Why should that be needed? It should be like this:

 public property int var {
    // int internalValue; // Automatically created (but named better)
    get { return internalValue; }
    set { internalValue = $; }
    void opIncrement() { internalValue++; }
 }

 In the minority of cases where a property doesn't need this variable,
 "internalValue" can just be optimized away.
If you really want that behavior, you should just use a public variable. Even changing it to a real property later would not matter for the public interface.
That's not quite why it was suggested. I actually like the idea. It is true that a public member would be preferred in the trivial case. In the general case though, people will have some internal value they are working with and whenever someone works with it they want side effects to happen. Here's an example: int nTimesVarRead = 0; public property int var { get { nTimesVarRead++; return internalValue; } set { internalValue = $; } } compare against: int nTimesVarRead = 0; int m_var; // Annoying extra declaration that is common practice. public property int var { get { nTimesVarRead++; return m_var; } set { m_var = $; } } Thus I rather like that idea. Perhaps, since the compiler knows the name of the property, the name of the generated internal value could just be the name of the property: public property int var { get { return var; } set { var = $; } } public property int foo { get { return foo; } set { foo = $; } } etc.
That I don't like, for the same reason VB's syntax for returning a value from a function drives me nuts: Function Foo Foo = 7 End Function It's a DRY violation. Anytime you change the name of Foo, it's just that much more that also needs to be updated. And if you copy it to use as a starting point for another function, then again you have that much more to update. Granted, that can all be solved with an refactoring feature in the editor, but if I wanted my language to be reliant on IDE features, I'd use Java. As long as it's come up, this is another case that frequently annoys me: template foo(alias a /*...*/) { const char[] foo = /*some fancy code-generation here*/; //pragma(msg, "foo: "~foo); // for debugging the template } mixin(foo!(/*...*/)); I do that frequently, and when developing them I'm constantly changing names, and ever time I do, I have to change the name and then copy-paste the new name to at least three other places. PITA.
Jan 08 2009
parent Chad J <gamerchad __spam.is.bad__gmail.com> writes:
Nick Sabalausky wrote:

 It's a DRY violation. 
I agree, good call.
Jan 08 2009
prev sibling parent reply Miles <_______ _______.____> writes:
Chad J wrote:
 I actually like the idea.
 
 (...)
 
 int nTimesVarRead = 0;
 
 public property int var
 {
     get
     {
         nTimesVarRead++;
         return internalValue;
     }
 
     set { internalValue = $; }
 }
That defeats one of the purposes of properties. A property is usually an accessor for some member variable. You have two concepts: the property and the member variable; they MUST be declared separately, since they may have different attributes. For example, the underlying member variable may have any of public, protected or private visibility, while the property may also have any of public, protected or private visibility. Usually, the member variable is either protected or private, while the property is either public or protected. Also, the class itself, and any inner scopes, may want to access the underlying member variable directly, without going through the property accessors.
 Perhaps, since the compiler knows the name of the property, the name of
 the generated internal value could just be the name of the property:
 
 public property int var
 {
     get { return var; }
     set { var = $; }
 }
That is the question... the property is public, but var is private or protected? How does the class access var without triggering the property accessors?
Jan 08 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Miles" <_______ _______.____> wrote in message 
news:gk68q1$19g1$1 digitalmars.com...
 Chad J wrote:
 I actually like the idea.

 (...)

 int nTimesVarRead = 0;

 public property int var
 {
     get
     {
         nTimesVarRead++;
         return internalValue;
     }

     set { internalValue = $; }
 }
That defeats one of the purposes of properties. A property is usually an accessor for some member variable. You have two concepts: the property and the member variable; they MUST be declared separately, since they may have different attributes. For example, the underlying member variable may have any of public, protected or private visibility, while the property may also have any of public, protected or private visibility. Usually, the member variable is either protected or private, while the property is either public or protected. Also, the class itself, and any inner scopes, may want to access the underlying member variable directly, without going through the property accessors.
This proposal doesn't prevent any of that. Suppose our syntax was like in the example above. I would still be able to do something like this: --------------- protected int _var; public property char[] var { // char[] internalValue is still defined, // but gets optimized away since it's never used. get { return ToString(_var); } set { _var = ToInt($); } } --------------- Also, we could say that the "internalValue" attribute of "private" (or protected, maybe we could have a way to optionally allow it to be protected) means "private to the class that contains the property" instead of "only accessible to the code within the property definition". Then we could do: --------------- class Foo { public property int myProp { get { return internalValue; } set { internalValue = $; } } public bar() { Stdout.formatln("{}", myProp.internalValue); } } --------------- Although I think I'm starting to really like the syntax being developed in another branch of this thread...(also I think I'm going to expand it a little): --------------- module foo; class Foo { public property int myProp { get { return this; } set { this = this.new; } } // Shorthand for the same trivial accessors in "myProp" public property int myShorthandProp { get; set; } public property int readOnlyProp { get { return 7; } } public property int writeOnlyProp { set; } public property int polysemousProp { set { this = this.new; } get { return this; } set char[] { this = StringToInt(this.new); } // If we ever got overload-on-return-value get char[] { return IntToString(this); } } private property int privateProp { get; set; } public property int anotherProp { /* Change access attribute of internal value, default could be either protected or private. This doesn't affect Foo's ability to see or not see the internal value. This only affects Foo subclasses and code outside the module. */ protected this; get; // Foo can access anotherProp's setter, but everything else sees anotherProp as read-only. private set; } public bar() { auto a = myProp; // Ok, uses getter auto b = myProp.this; // Ok, internal value auto c = privateProp; // Ok, uses getter auto d = privateProp.this; // Ok, internal value auto e = writeOnlyProp; // Error: no getter auto f = writeOnlyProp.this; // Ok, since we're inside Foo } } module main; void main() { auto foo = new Foo(); auto a = myProp; // Ok, uses getter auto b = myProp.this; // Error: internal value is private to Foo auto c = privateProp; // Error: privateProp is private auto c = privateProp.this; // Error: privateProp is private auto e = writeOnlyProp; // Error: no getter auto f = writeOnlyProp.this; // Error: internal value is private to Foo } ---------------
 Perhaps, since the compiler knows the name of the property, the name of
 the generated internal value could just be the name of the property:

 public property int var
 {
     get { return var; }
     set { var = $; }
 }
That is the question... the property is public, but var is private or protected? How does the class access var without triggering the property accessors?
See above.
Jan 08 2009
parent Miles <_______ _______.____> writes:
Nick Sabalausky wrote:
 This proposal doesn't prevent any of that. Suppose our syntax was like in 
 the example above. I would still be able to do something like this:
 
 ---------------
 protected int _var;
 public property char[] var
 {
     // char[] internalValue is still defined,
     // but gets optimized away since it's never used.
 
     get { return ToString(_var); }
     set { _var = ToInt($); }
 }
 ---------------
The problem I see with this is that it complicates the implementation of properties. Properties are just collections of delegates, perhaps even optimized to contain only a single frame pointer for multiple function pointers. Properties may appear in contexts where you can't have member variables (e.g., interfaces).
 ---------------
 class Foo
 {
     public property int myProp
     {
         get { return internalValue; }
         set { internalValue = $; }
     }
 
     public bar()
     {
         Stdout.formatln("{}", myProp.internalValue);
     }
 }
 ---------------
Won't work, not like that. For the compiler, that is difficult to distinguish from calling the getter for myProp (that returns an int), and trying to access a member variable called "internalValue" from that int instance. The compiler could provide some syntax to disambiguate property's members from it's value's members. Perhaps: property(myProp).internalValue; In this case, property(...) tells the compiler to handle the argument as the property itself, without calling the getter. But requiring that syntax just sucks. I find it better to have the value in another variable.
Jan 09 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Michiel Helvensteijn" <nomail please.com> wrote in message 
news:gk5b4m$2ekd$1 digitalmars.com...
 Nick Sabalausky wrote:


 "get". They're always going to be the same. In the case of "set", it's
 always going to be just the one param, and it'll be the new value, so 
 just
 make a special predefined var. Something like:

 get { return this.len; }

 like that
I have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number.
I don't think that follows at all. Function parameters have user-definable names because functions are a general concept that, for all the syntax is aware, could have any number of params that could each represent just about anything. Property getters/setters are different: A property getter is ALWAYS going to take nothing in and return a value of the same type as the property that represents the value of the property. Otherwise it wouldn't be a property getter. A property setter is ALWAYS going to return nothing and take in exactly one argument, of the same type as the property, and that value will ALWAYS represent the intended new value. Otherwise it wouldn't be a property setter. With this information, requiring a custom user-defined name for the setter parameter becomes completely frivolous. You may as well require people to make up their own names for "void", "if", "while" and "{some array here}.length": they're always going to mean the same thing so it's much better to have it standardized.
 set has a parameter, and
 the programmer should be able to name it.

 Also, removing the parentheses would be confusing. I believe it might be
 better to make them look like this, even:

 property int length {
    auto get() { .. }
    void set(auto name) { .. }
 }

 So they would clearly be function declarations.
What benefit would that provide? Downside: The fact that they're part of the language-defined property getter/setter syntax renders any explicitly-stated parameter and return-value information completely redundant. Of course, I'm aware that sometimes redundancy can be good since it can help catch errors, but this particular redundancy doesn't do anything to help catch errors. In fact, it could cause confusion because it obscures the fact that "get" and "set" are special function names within {} set{}") I suppose explicitly stating the return type and parameter lists could open the door for "multitype" properties that could "get" or "set" different types without relying on the caller to cast/convert. I'm not sure how I feel about that though...it might be nice...
 2. You shouldn't have to manually define a private var to go along with
 the property. In languages with real properties, the following idiom is
 used constantly:

 private int _var;
 public property int var {
    get { return _var; }
    set { _var = $; }
    void opIncrement() { _var++; }
 }

 Why should that be needed? It should be like this:

 public property int var {
    // int internalValue; // Automatically created (but named better)
    get { return internalValue; }
    set { internalValue = $; }
    void opIncrement() { internalValue++; }
 }

 In the minority of cases where a property doesn't need this variable,
 "internalValue" can just be optimized away.
If you really want that behavior, you should just use a public variable. Even changing it to a real property later would not matter for the public interface.
The bodies of those get's and set's were just trivial examples. I agree an actual property like that would be pointless. But a typical use-case for properties is to intercept accesses to a member variable and perform some sort of action on each access (validation, logging, updating a related value, etc). In other words, you still frequently need the "private int _x; property int x {}" idiom. In my experience, these sorts of things are the most common uses for properties, and even if they weren't it would be simple enough to optimize away the implied private var whenever it's not needed, so the feature would never cause any trouble, it would just help in many cases (plus provide a standardized name).
Jan 08 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:gk5fo7$2m80$1 digitalmars.com...
 "Michiel Helvensteijn" <nomail please.com> wrote in message 
 news:gk5b4m$2ekd$1 digitalmars.com...
 Nick Sabalausky wrote:


 and
 "get". They're always going to be the same. In the case of "set", it's
 always going to be just the one param, and it'll be the new value, so 
 just
 make a special predefined var. Something like:

 get { return this.len; }

 like that
I have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number.
I don't think that follows at all. Function parameters have user-definable names because functions are a general concept that, for all the syntax is aware, could have any number of params that could each represent just about anything. Property getters/setters are different: A property getter is ALWAYS going to take nothing in and return a value of the same type as the property that represents the value of the property. Otherwise it wouldn't be a property getter. A property setter is ALWAYS going to return nothing and take in exactly one argument, of the same type as the property, and that value will ALWAYS represent the intended new value. Otherwise it wouldn't be a property setter. With this information, requiring a custom user-defined name for the setter parameter becomes completely frivolous. You may as well require people to make up their own names for "void", "if", "while" and "{some array here}.length": they're always going to mean the same thing so it's much better to have it standardized.
Sorry, Ary beat me to it. And much less verbosely ;)
Jan 08 2009
prev sibling parent reply Miles <_______ _______.____> writes:
Nick Sabalausky wrote:
 A property setter is ALWAYS going to return nothing and
Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables. Something that is possible with member variables MUST also be possible with properties, in a transparent way for any code outside the class. For example: button.width = button.height = 50; // makes a square button Optimally, this should expand to either: button._set_width(button._set_height(50)); or button._set_height(50); button._set_width(button._get_height()); From the compiler point-of-view, the first is easier to implement.
 take in exactly one argument, of the same type as the property,
 and that value will ALWAYS represent the intended new value.
Also not true. It is fine to have method polymorphism for the setter. You may want to define property set(int value), set(Bigint value) and set(float value), all with different semantics.
Jan 08 2009
next sibling parent reply "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:
 Nick Sabalausky wrote:
 A property setter is ALWAYS going to return nothing and
Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue. Returning a straight 'ref T' is pretty much the same as making the member variable public, in terms of the encapsulation it gives you. class Foo { private int _data; ref int data() { return _data; } void data(int d) { data = d; do_something_very_important(); } } auto foo = new Foo; int*allyourdataisbelongtome = &Foo.data; Bye bye encapsulation. Now I can change your data all I want without you noticing. Also it means if I later realize I actually wanted data to be a float internally, I still have to keep an int member around to satisfy any client code that depends on getting an integer lvalue back. What I would like to see happen is that if a property setter doesn't return an lvalue, then the compiler will jigger things around to do everything in terms of calls to the setter. If it does return an lvalue then it will use it directly.
 Something
 that is possible with member variables MUST also be possible with
 properties, in a transparent way for any code outside the class.

 For example:

        button.width = button.height = 50;      // makes a square button
I agree that that should expand to something sensible, but that example doesn't actually require the setters to return an lvalue. A regular rvalue is fine for that. You'd only need to return an lvalue for something like: (button.height=50) += 3; Or for something like change_integer( button.height = 50 ); where change_integer takes a ref int. Using the lvalue returned from a property assignment is really not that common I think. Maybe I'm missing some big use case though. On the other hand, things like ++x do get used as lvalues more commonly I think. I'm fond of doing ++x%=N as a way to do a wrapped increment. :-) In C++, anyway. In D it gives me "x += 1 is not an lvalue". --bb
Jan 08 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Bill Baxter" <wbaxter gmail.com> wrote in message 
news:mailman.343.1231465331.22690.digitalmars-d puremagic.com...
 On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:
 Nick Sabalausky wrote:
 A property setter is ALWAYS going to return nothing and
Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue.
He said "rvalue", not "lvalue". I actually made that same mistake the first couple times I read it.
Jan 08 2009
parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Jan 9, 2009 at 10:58 AM, Nick Sabalausky <a a.a> wrote:
 "Bill Baxter" <wbaxter gmail.com> wrote in message
 news:mailman.343.1231465331.22690.digitalmars-d puremagic.com...
 On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:
 Nick Sabalausky wrote:
 A property setter is ALWAYS going to return nothing and
Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue.
He said "rvalue", not "lvalue". I actually made that same mistake the first couple times I read it.
Wow. You're right. Maybe I need to change my font or something. Sorry for the rant about returning lvalues then! --bb
Jan 08 2009
prev sibling parent reply Miles <_______ _______.____> writes:
Bill Baxter wrote:
 On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:
 Both the getter and the setter should return an rvalue. Properties exist
 so that they are interchangeable with real member variables.
Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue.
Wait! Read again what I said... getters and setters should return an *rvalue*, not lvalue. Everything else you said was based on the idea that accessors return lvalues, that wasn't what I said... There are some very special conditions where the getter MAY return an lvalue. But nothing else. The setter always returns rvalues. For example, if prop is a common property, defined as: public property int width { get() { return m_width; } set(Point value) { return m_width = value; } } Then the following code: x.width += 5; Should expand to something like (hopefully, optimized as far as possible): { auto tmp = x._get_width(); tmp += 5; x._set_width(tmp); } On the other hand, if the getter is defined to return an lvalue, like (tentative syntax): public property int width { ref get() { return m_width; } set(Point value) { return m_width = value; } } Then the compiler should be able to optimize the same code further: x._get_width() += 5; The same for member function calls if the property type is a structure or class.
Jan 08 2009
parent "Bill Baxter" <wbaxter gmail.com> writes:
On Fri, Jan 9, 2009 at 11:01 AM, Miles <_______ _______.____> wrote:
 Bill Baxter wrote:
 On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:
 Both the getter and the setter should return an rvalue. Properties exist
 so that they are interchangeable with real member variables.
Partly, but also properties exist to provide encapsulation of private state. So you gotta be careful when you say they should always return an lvalue.
Wait! Read again what I said... getters and setters should return an *rvalue*, not lvalue. Everything else you said was based on the idea that accessors return lvalues, that wasn't what I said... There are some very special conditions where the getter MAY return an lvalue. But nothing else. The setter always returns rvalues. For example, if prop is a common property, defined as: public property int width { get() { return m_width; } set(Point value) { return m_width = value; } } Then the following code: x.width += 5; Should expand to something like (hopefully, optimized as far as possible): { auto tmp = x._get_width(); tmp += 5; x._set_width(tmp); } On the other hand, if the getter is defined to return an lvalue, like (tentative syntax): public property int width { ref get() { return m_width; } set(Point value) { return m_width = value; } } Then the compiler should be able to optimize the same code further: x._get_width() += 5; The same for member function calls if the property type is a structure or class.
Ok! I'm in agreement with you totally on all that. Sorry for the lvalue/rvalue mixup. --bb
Jan 08 2009
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Miles" <_______ _______.____> wrote in message 
news:gk67hr$17d9$1 digitalmars.com...
 Nick Sabalausky wrote:
 A property setter is ALWAYS going to return nothing and
Both the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables. Something that is possible with member variables MUST also be possible with properties, in a transparent way for any code outside the class. For example: button.width = button.height = 50; // makes a square button Optimally, this should expand to either: button._set_width(button._set_height(50)); or button._set_height(50); button._set_width(button._get_height()); From the compiler point-of-view, the first is easier to implement.
True, but my main point was, however the language ends up handling the details of property getters/setters, it's not going to be as general as ordinary functions, and thus certain aspects of the syntax can/should be simplified. But regarding your examples up there, the first form might be easier for the compiler to implement, but I think the second would be overall better. You're absolutely right that properties need to be able to return an rvalue from an assignment, but I see no reason why that can't or shouldn't be transparent to the person writing the property.
 take in exactly one argument, of the same type as the property,
 and that value will ALWAYS represent the intended new value.
Also not true. It is fine to have method polymorphism for the setter. You may want to define property set(int value), set(Bigint value) and set(float value), all with different semantics.
I'm still not 100% convinced that we should be using properties to do type conversions, although I suppose it may have some legitimate uses... I guess I'm just afraid of ending up with a situation where people start feeling compelled to make all of their properties explicitly compatible with every type under the sun. All of a sudden we'd be heading towards all-out dynamic typing, and start losing the benefits of static typing, and, and...then the sun explodes...or something...(I should stay off that slippery slope...) But anyway, even with the possibility of a property handling multiple types, I still don't think it means we can't or shouldn't have a nicely trimmed syntax for the more typical cases: property int x { set { this = this.new; } get { return this; } set char[] { this = StringToInt(this.new); } get char[] { return IntToString(this); } // If we ever got overload-on-return-value }
Jan 08 2009
parent reply Miles <_______ _______.____> writes:
Nick Sabalausky wrote:
 True, but my main point was, however the language ends up handling the 
 details of property getters/setters, it's not going to be as general as 
 ordinary functions, and thus certain aspects of the syntax can/should be 
 simplified.
In this case, simplifying would be more complex. Under the hood, when you define getters and setters, you are defining functions, and function overloading is an inherent feature of the language. In fact, the current "property" feature of D already supports many overloaded setters for different types, since they are just normal functions. For example, consider the property definition: public property int width { get() { return width; } set(int value) { width = value; } set(float value) { width = value + 0.5; } } That would generate overloaded functions with different signatures, lets say that, under the hood, the compiler generates: int __get_width(); int __set_width(int value); int __set_width(float value); Then, when code that accesses the property is compiled, something that looks like width = x; will, in fact, be threated as __set_width(x); and so, the compiler will choose the appropriate __set_width() function with the signature that matches the above call. So, restricting a property to have only a single setter will end up creating unnecessary restrictions for something that is already native to the language.
 You're absolutely right that properties need to be able to return an rvalue 
 from an assignment, but I see no reason why that can't or shouldn't be 
 transparent to the person writing the property.
They could, no problem.
 I'm still not 100% convinced that we should be using properties to do type 
 conversions, although I suppose it may have some legitimate uses...
It is not just about type conversions... it is that the feature is already something natural for the language.
 But anyway, even with the possibility of a property handling multiple types, 
 I still don't think it means we can't or shouldn't have a nicely trimmed 
 syntax for the more typical cases:
 
 property int x
 {
     set { this = this.new; }
     get { return this; }
 
     set char[] { this = StringToInt(this.new); }
     get char[] { return IntToString(this); } // If we ever got 
 overload-on-return-value
 }
Not for getters, please... the type of the getter should be the type of the property, or that would create a lot of complexity for the language (that is also the reason you don't overload functions based on the return type).
Jan 08 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Miles" <_______ _______.____> wrote in message 
news:gk6f9p$1jve$1 digitalmars.com...
 Nick Sabalausky wrote:
 True, but my main point was, however the language ends up handling the
 details of property getters/setters, it's not going to be as general as
 ordinary functions, and thus certain aspects of the syntax can/should be
 simplified.
In this case, simplifying would be more complex. Under the hood, when you define getters and setters, you are defining functions, and function overloading is an inherent feature of the language. In fact, the current "property" feature of D already supports many overloaded setters for different types, since they are just normal functions. For example, consider the property definition: public property int width { get() { return width; } set(int value) { width = value; } set(float value) { width = value + 0.5; } } That would generate overloaded functions with different signatures, lets say that, under the hood, the compiler generates: int __get_width(); int __set_width(int value); int __set_width(float value); Then, when code that accesses the property is compiled, something that looks like width = x; will, in fact, be threated as __set_width(x); and so, the compiler will choose the appropriate __set_width() function with the signature that matches the above call. So, restricting a property to have only a single setter will end up creating unnecessary restrictions for something that is already native to the language.
 You're absolutely right that properties need to be able to return an 
 rvalue
 from an assignment, but I see no reason why that can't or shouldn't be
 transparent to the person writing the property.
They could, no problem.
 I'm still not 100% convinced that we should be using properties to do 
 type
 conversions, although I suppose it may have some legitimate uses...
It is not just about type conversions... it is that the feature is already something natural for the language.
Ok, you've convinced me on this.
 But anyway, even with the possibility of a property handling multiple 
 types,
 I still don't think it means we can't or shouldn't have a nicely trimmed
 syntax for the more typical cases:

 property int x
 {
     set { this = this.new; }
     get { return this; }

     set char[] { this = StringToInt(this.new); }
     get char[] { return IntToString(this); } // If we ever got
 overload-on-return-value
 }
Not for getters, please... the type of the getter should be the type of the property, or that would create a lot of complexity for the language (that is also the reason you don't overload functions based on the return type).
Well, like I said, *If* we were to get overload-on-return-value. Not that I'm itching for it or anything. I've just seen the idea discussed before and if it hypothetically were to happen, then the above could work as a getter equivilent.
Jan 08 2009
parent reply Miles <_______ _______.____> writes:
Nick Sabalausky wrote:
 Well, like I said, *If* we were to get overload-on-return-value. Not that 
 I'm itching for it or anything. I've just seen the idea discussed before and 
 if it hypothetically were to happen, then the above could work as a getter 
 equivilent.
Ok. But I think such feature would create a mess. For example: int func1() { ... } char[] func1() { ... } void func2(int x) { ... } void func2(char[] x) { ... } func2(func1()); // what is the expected behavior? When you are inferring types, you need somewhere to anchor the compiler decision, either on the sender or on the receiver side.
Jan 09 2009
parent "Nick Sabalausky" <a a.a> writes:
"Miles" <_______ _______.____> wrote in message 
news:gk7fau$f38$1 digitalmars.com...
 Nick Sabalausky wrote:
 Well, like I said, *If* we were to get overload-on-return-value. Not that
 I'm itching for it or anything. I've just seen the idea discussed before 
 and
 if it hypothetically were to happen, then the above could work as a 
 getter
 equivilent.
Ok. But I think such feature would create a mess. For example: int func1() { ... } char[] func1() { ... } void func2(int x) { ... } void func2(char[] x) { ... } func2(func1()); // what is the expected behavior? When you are inferring types, you need somewhere to anchor the compiler decision, either on the sender or on the receiver side.
Like I said, I'm neither advocating nor condemning overload-on-return-value.
Jan 09 2009
prev sibling parent reply Chad J <gamerchad __spam.is.bad__gmail.com> writes:
Miles wrote:
 
 Both the getter and the setter should return an rvalue. Properties exist
 so that they are interchangeable with real member variables. Something
 that is possible with member variables MUST also be possible with
 properties, in a transparent way for any code outside the class.
 
I agree, though let's not fool ourselves, there is at least one corner case: property int foo { get{ ... } set{ ... } } auto bar = &foo; what happens when someone writes this? though I'd love it if there was a better way.
Jan 08 2009
next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Chad J wrote:
 Miles wrote:
 Both the getter and the setter should return an rvalue. Properties exist
 so that they are interchangeable with real member variables. Something
 that is possible with member variables MUST also be possible with
 properties, in a transparent way for any code outside the class.
I agree, though let's not fool ourselves, there is at least one corner case: property int foo { get{ ... } set{ ... } } auto bar =&foo; what happens when someone writes this? though I'd love it if there was a better way.
that's solvable. as I noted in a previous post, a property seems to me to be mainly syntax sugar for a struct like in the following snippet: class A { struct Prop { int internal; int opCall() { return internal; } void opAssign(int value) { internal = value; } } public Prop prop; ... } void main() { auto a = new A; int num = a.prop; a.prop = 9; auto foo = &a.prop; // what happens here? ... } foo can be the address of "prop" (struct instance) in the above code. this means that: *foo = ...; is translated to *foo.opAssign(...); and similarly: auto bar = *foo; will be auto bar = *foo.opCall(); the only issue here is what will be the type of foo if D provides the syntax sugar for all this. maybe define such types as special property types - for a given property "foo" in class "Bar" the type of the property will be "Bar.__fooPropertyType".
Jan 09 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-01-09 05:47:26 -0500, Yigal Chripun <yigal100 gmail.com> said:

 that's solvable. as I noted in a previous post, a property seems to me 
 to be mainly syntax sugar for a struct like in the following snippet:
 
 class A {
 	struct Prop {
 		int internal;
 		int opCall() { return internal; }
 		void opAssign(int value) { internal = value; }
 	}
 	public Prop prop;
 	...
 }
Hum, that doesn't really work. Getter and setters of the property have access to the whole class scope, and can call functions of that class. If you wanted to extract a property from a class, you'd have to do it by keeping a pointer to the class, not the property's value: class A { private int internal; struct Prop { A outerClass; int opCall() { return outerClass.internal; } void opAssign(int value) { outerClass.internal = value; } } public Prop prop; } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 09 2009
parent Yigal Chripun <yigal100 gmail.com> writes:
Michel Fortin wrote:
 On 2009-01-09 05:47:26 -0500, Yigal Chripun <yigal100 gmail.com> said:

 that's solvable. as I noted in a previous post, a property seems to me
 to be mainly syntax sugar for a struct like in the following snippet:

 class A {
 struct Prop {
 int internal;
 int opCall() { return internal; }
 void opAssign(int value) { internal = value; }
 }
 public Prop prop;
 ...
 }
Hum, that doesn't really work. Getter and setters of the property have access to the whole class scope, and can call functions of that class. If you wanted to extract a property from a class, you'd have to do it by keeping a pointer to the class, not the property's value: class A { private int internal; struct Prop { A outerClass; int opCall() { return outerClass.internal; } void opAssign(int value) { outerClass.internal = value; } } public Prop prop; }
instead of manually doing it within the struct just do s/struct/class to my code. this will solve it since inner classes have an "outer" pointer to the containing class instance. I wasn't trying to give the best and most general solution, just to point out that there is a straight forward solution to this.
Jan 09 2009
prev sibling parent Miles <_______ _______.____> writes:
Chad J wrote:
 I agree, though let's not fool ourselves, there is at least one corner case:
 
 property int foo
 {
     get{ ... }
     set{ ... }
 }
 
 auto bar = &foo;
 what happens when someone writes this?
Yes, this is a corner case. If the getter is not set to return an lvalue, that makes as much sense as trying to get a reference from an rvalue, like &5.

 though I'd love it if there was a better way.
That is expected behavior. Although able to emulate variables, properties are not variables, and neither functions. They could be seen as a collection of delegates. In some cases, the compiler may allow you to retrieve individual delegates from the property through some syntax, like: auto bar = & property(foo).get;
Jan 09 2009
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Michiel Helvensteijn wrote:
 [Condensed: syntax sucks, let's introduce more!]
I might be old fashioned (get offa mah lawn!), but I've always found something like the following quite acceptable: class Foo { mixin(properties (" rw int bar; ro float baz; wo Foo zyzzy; ")); } I know I had a CTFE function lying around that would parse that and but with CTFE/templates and string mixins, we can have whatever syntax we damn well want. Hell, I used this in a prototype game engine to generate CVars; it'd generate the properties, the backing store, the hooking code, event registration, etc. One line generated about 10-20 lines of boilerplate Why change the language when you can just abuse it's already-existing features? :D -- Daniel "downs is my hero"
Jan 09 2009
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Daniel Keep (daniel.keep.lists gmail.com)'s article
 Why change the language when you can just abuse it's already-existing
 features? :D
    -- Daniel "downs is my hero"
This is precisely the attitude that left C++ with all of the cruft and baggage it has. Yes, if something can be implemented *elegantly, efficiently, and with clean syntax* in a library, then it doesn't belong in the core language. Yes, powerful language features like templates, mixins, operator overloading, etc. are great for abusing when you need something that's not universal enough to be in the core language. The flip side is that, the more you rely on libraries (whether your personal snippet library or an "official" library) that use hacks like this, the more you're building a house of cards. When you build hacks on top of other hacks, and build these on top of still more hacks (think STL), you're basically asking ugly syntax, odd corner cases, and the exposure of obscure implementation bugs. This is why things like arrays, strings and delegates belong in the core language. Since properties are just as universal, I believe the same argument can be made for them.
Jan 09 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
dsimcha wrote:
 == Quote from Daniel Keep (daniel.keep.lists gmail.com)'s article
 Why change the language when you can just abuse it's already-existing
 features? :D
    -- Daniel "downs is my hero"
This is precisely the attitude that left C++ with all of the cruft and baggage it has. Yes, if something can be implemented *elegantly, efficiently, and with clean syntax* in a library, then it doesn't belong in the core language. Yes, powerful language features like templates, mixins, operator overloading, etc. are great for abusing when you need something that's not universal enough to be in the core language.
Well I'm not so sure about that. In fact I'd go as far as saying you're contradicting yourself. The cruft and baggage is exactly left by unsuccessful language features that had to stay because, well, they were IN the language. For a good while, C++ has been rather liberal in adopting new and risky language features (exceptions, multiple inheritance, templates...) In contrast, for most of its existence, C++ has had an extremely thin library. An example of a bad library from the old days is iostreams, but hardly anyone considers that a major issue. It's not cruft and it's not baggage. It just sucks. :o) So your own logic inexorably leads to a conclusion opposite to your hypothesis: it's best to keep the language lean and keep one's options open, lest cruft and baggage will accumulate. Of course that, taken to an extreme, can lead to contortions and can do more harm than good. So moderation is likely the best way to go.
 The flip side is that, the more you rely on libraries (whether your personal
 snippet library or an "official" library) that use hacks like this, the more
 you're building a house of cards.
That's a bit odd. Are you saying that libraries are inherently less reliable than language features?
 When you build hacks on top of other hacks, and
 build these on top of still more hacks (think STL), you're basically asking
ugly
 syntax, odd corner cases, and the exposure of obscure implementation bugs. 
This
 is why things like arrays, strings and delegates belong in the core language.
 Since properties are just as universal, I believe the same argument can be made
 for them.
When I "think STL" I'm thinking of the best-defined library of general containers and algorithms. No other library I know goes to a longer length at defining its own behavior. Knowing STL makes me look with a rather critical eye at the loosely-defined libraries that accomplish (often sloppily) similar tasks usually featured with other languages. Andrei
Jan 09 2009
parent dsimcha <dsimcha yahoo.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)
 Well I'm not so sure about that. In fact I'd go as far as saying you're
 contradicting yourself. The cruft and baggage is exactly left by
 unsuccessful language features that had to stay because, well, they were
 IN the language. For a good while, C++ has been rather liberal in
 adopting new and risky language features (exceptions, multiple
 inheritance, templates...) In contrast, for most of its existence, C++
 has had an extremely thin library. An example of a bad library from the
 old days is iostreams, but hardly anyone considers that a major issue.
 It's not cruft and it's not baggage. It just sucks. :o)
 So your own logic inexorably leads to a conclusion opposite to your
 hypothesis: it's best to keep the language lean and keep one's options
 open, lest cruft and baggage will accumulate.
 Of course that, taken to an extreme, can lead to contortions and can do
 more harm than good. So moderation is likely the best way to go.
I will admit that cruft and baggage were probably poor word choices to describe what I meant. I really meant things like odd syntax and weird corner cases caused by not having the core language know about very basic, frequently used things like arrays and strings.
 The flip side is that, the more you rely on libraries (whether your personal
 snippet library or an "official" library) that use hacks like this, the more
 you're building a house of cards.
That's a bit odd. Are you saying that libraries are inherently less reliable than language features?
In a way, yes. When building a feature into a language, you can do literally *anything* that is computationally feasible, such as define new syntax, make the compiler "know" about the feature at a high level, display good high-level error messages, etc. When you're defining something in a library, you're limited by existing constructs. Sometimes those existing constructs are enough to do what you want cleanly and elegantly. Sometimes (as in the OP's example) you have to resort to hacks. My point is that, when you have a low-level library feature A that's kind of a hack and does strange things in certain edge/error/unanticipated cases, and then you build a high-level library feature B on top of A using still more hacks, what are the odds that if something goes wrong with B, anyone will have any clue why? What are the odds that B won't have some frustrating, arbitrary limitations?
 When you build hacks on top of other hacks, and
 build these on top of still more hacks (think STL), you're basically asking
ugly
 syntax, odd corner cases, and the exposure of obscure implementation bugs. 
This
 is why things like arrays, strings and delegates belong in the core language.
 Since properties are just as universal, I believe the same argument can be made
 for them.
When I "think STL" I'm thinking of the best-defined library of general containers and algorithms. No other library I know goes to a longer length at defining its own behavior. Knowing STL makes me look with a rather critical eye at the loosely-defined libraries that accomplish (often sloppily) similar tasks usually featured with other languages. Andrei
Yes, STL (and Boost, etc.) are very high-quality libraries. The problem is that, because the core language doesn't "understand" anything in them, there's no shortage of things like clumsy syntax, inscrutible error messages for the tiniest errors, etc. This is not to say that all, or even most, of STL or Boost belong in the core C++ language, just the features that are both heavily used and would benefit greatly from the core language "understanding" them.
Jan 09 2009
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:gk7nij$rlo$1 digitalmars.com...
 Michiel Helvensteijn wrote:
 [Condensed: syntax sucks, let's introduce more!]
I might be old fashioned (get offa mah lawn!), but I've always found something like the following quite acceptable: class Foo { mixin(properties (" rw int bar; ro float baz; wo Foo zyzzy; ")); } I know I had a CTFE function lying around that would parse that and but with CTFE/templates and string mixins, we can have whatever syntax we damn well want. Hell, I used this in a prototype game engine to generate CVars; it'd generate the properties, the backing store, the hooking code, event registration, etc. One line generated about 10-20 lines of boilerplate Why change the language when you can just abuse it's already-existing features? :D -- Daniel "downs is my hero"
String mixins are very powerful, and certainly welcome IMO, but they involve dynamically generating code by algorithmically splicing together little text snippets, and that's just very hack-ish. It's literally just like using classic-style ASP or PHP. That was too clumbsy even for the already-clumbsiness-embracing world of the web; that's why they're moving towards proper page-templating engines. I see the role of string mixins as being a handy way to hack together a piece of advanced functionality until a better more proper way comes along.
Jan 09 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Nick Sabalausky wrote:
 String mixins are very powerful, and certainly welcome IMO, but they involve 
 dynamically generating code by algorithmically splicing together little text 
 snippets, and that's just very hack-ish. It's literally just like using 
 classic-style ASP or PHP. That was too clumbsy even for the 
 already-clumbsiness-embracing world of the web; that's why they're moving 
 towards proper page-templating engines. I see the role of string mixins as 
 being a handy way to hack together a piece of advanced functionality until a 
 better more proper way comes along. 
I think the comparison is a bit loose; the problem with ASP and PHP was the way most people mixed processing logic and display. Here, there's a relatively clean separation. Yes, a language-level construct for this would be nice, but where do you draw the line? Personally, I'm a big believer in generic constructs. Let's pretend for a moment that we've got AST macros, and can specify that our macro uses { } instead of ( )... properties { rw int foo; ro float bar; } That might as well be a language construct! And D isn't as bad as C/C++ when it comes to inscrutible error messages; we at least have pragma(msg), although I admit it would be nice to have more control over where the compiler says an error comes from, and what the code responsible is. At the end of the day, my job is to make a computer do stuff. If string mixins help me reach that goal quicker [1], then I'm all for it. -- Daniel [1] Obviously, I don't mean "at all costs;" something like: mixin(/* a long, complex expression that produces a string */); is pretty obviously a bad idea for exactly the reasons you gave above. Something like: mixin(hhfk("kjiq9238*)&70394{")); is also a bad idea, for rather obvious reasons.
Jan 09 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:gk8j4h$29fm$1 digitalmars.com...
 Nick Sabalausky wrote:
 String mixins are very powerful, and certainly welcome IMO, but they 
 involve dynamically generating code by algorithmically splicing together 
 little text snippets, and that's just very hack-ish. It's literally just 
 like using classic-style ASP or PHP. That was too clumbsy even for the 
 already-clumbsiness-embracing world of the web; that's why they're moving 
 towards proper page-templating engines. I see the role of string mixins 
 as being a handy way to hack together a piece of advanced functionality 
 until a better more proper way comes along.
I think the comparison is a bit loose; the problem with ASP and PHP was the way most people mixed processing logic and display. Here, there's a relatively clean separation.
It's not so much an issue of logic vs display (if you're using a somewhat literal definition of "display"), as it is an issue of proper ways to dynamically generate code regardless of whether the generated output is a "display" description or a description of yet more logic (ex, generating client-side JavaScript using classic ASP/PHP techniques is still rightly considered just as bad as if HTML were being generated). With that in mind, how do D string mixins have more logic/output separation than typical ASP or PHP? The actual implementation of the string-generating function (or template) still mixes logic with output. Suppose you wanted to make a mixin that generated a bunch of int declarations from a list of names. How would you implement that? With current D, it would have to be something like this: / / Pseudocode declareStuff(string[] names) // template or CTFE { // Template-style would be mostly the same, // but maybe slightly more functional than imperative. string str; foreach(name; names) str ~= "int "~name~";\n"; // \n helps with debugging return str; } Now compare that to a fairly typical method for generating a list in classic-ASP/PHP: / / Pseudocode generateList(string[] listElements) { string str= "<ul>"; foreach(elem; listElements) str ~= "<li>"~elem~"</li>\n"; return str~"</ul>"; } It's practically the same code, except that the web development world has been discovering that's in a bad style that leads to problems. Although, maybe string mixins could make use of proper logic/output separation if we had better CTFE. Then we could use something like ANTLR's StringTemplate lib. But maybe that would lead to unnecessarily long compile times? In any case, whenever I see "mixin(...);", even in my own code, I always think "hack". That's fine for obscure special-domain tools, but for something as common and as general as properties, it just comes across as a big kludge.
 Yes, a language-level construct for this would be nice, but where do you 
 draw the line?
IMO, Somewhere beyond "property syntax" ;-)
 Personally, I'm a big believer in generic constructs.  Let's pretend for a 
 moment that we've got AST macros, and can specify that our macro uses { } 
 instead of ( )...

 properties
 {
     rw int foo;
     ro float bar;
 }
If we had AST macros, and creating them was significantly cleaner than creating string mixins, then that would certainly reduce the need for language-level things like properties. However, I would still very much insist that something as common as properties would, at the very least, be part of the standard library. It wouldn't be good for the language to have twenty different custom property-syntax libs floating around.
Jan 09 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 In any case, whenever I see "mixin(...);", even in my own code, I always 
 think "hack". That's fine for obscure special-domain tools, but for 
 something as common and as general as properties, it just comes across as a 
 big kludge.
I agree. String mixin are generally near-unreadable, and I hate to debug them. So it's better to use them as little as possible. If many D programs show a very common pattern (like certain usages of properties) it becomes a candidate to be included into the compiler and not done with string mixings anymore. (This also means you can see string mixings as feature laboratories: that is tests of features that may be added to future versions of the language. Just like plugins in Firefox). Bye, bearophile
Jan 09 2009
prev sibling parent reply =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Daniel Keep wrote:
 
 
 Michiel Helvensteijn wrote:
 [Condensed: syntax sucks, let's introduce more!]
I might be old fashioned (get offa mah lawn!), but I've always found something like the following quite acceptable: class Foo { mixin(properties (" rw int bar; ro float baz; wo Foo zyzzy; ")); }
Note that this is a very limited use for properties. Defining properties isn't just a question of access control (read/write, read only, or write only). It is also a way to execute arbitrary code each time the value is changed (or accessed), or to create properties that don't correspond to actual data fields (complex module and argument come to mind). How would you do that with mixins? (Not that it would be impossible, but the syntax would probably be horrible). Jerome - -- mailto:jeberger free.fr http://jeberger.free.fr Jabber: jeberger jabber.fr -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAklocvAACgkQd0kWM4JG3k8NCwCgm0+e/mOg3pfhpaqlnCGad/tA v2UAmwXZjHfyeGdLk5C2FthJxOW+924r =RNrq -----END PGP SIGNATURE-----
Jan 10 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Jérôme M. Berger wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 Daniel Keep wrote:
 Michiel Helvensteijn wrote:
 [Condensed: syntax sucks, let's introduce more!]
I might be old fashioned (get offa mah lawn!), but I've always found something like the following quite acceptable: class Foo { mixin(properties (" rw int bar; ro float baz; wo Foo zyzzy; ")); }
Note that this is a very limited use for properties. Defining properties isn't just a question of access control (read/write, read only, or write only).
For me, it *was* a case of access-control... at least, it was about 80% of the time. I'm a fan of interface-heavy design: make an interface for every distinct kind of functionality and pack them all together. That means I end up with a metric buttload (equivalent to about 42 imperial piles) of properties. And most of them were just accessors that needed to be in the interface; hence the functionality of the mixin.
 It is also a way to execute arbitrary code
 each time the value is changed (or accessed), ...
It's been a while since I used the code, and honestly I can't seem to track it down, but I recall that I could do this: mixin(properties(" rw int bar; ")); protected void bar_onSet(int newValue) { ... } There was also an *_onGet, and you could block setting a property by throwing an exception, I believe. Granted, this doesn't cover every possible use-case, but then it's not supposed to; it's supposed to make the 90% easier. It still did the assignment, since I felt you shouldn't be making properties that have a setter that doesn't set anything...
 ... or to create
 properties that don't correspond to actual data fields (complex
 module and argument come to mind).
If the property doesn't correspond to a physical field, then you're going to have to write the code to handle it from scratch. And no matter WHAT you do, it's eventually going to boil down to one or more functions. Which is EXACTLY how they currently work. What would be the point of making a special syntax when you can already do that? :P
 How would you do that with
 mixins? (Not that it would be impossible, but the syntax would
 probably be horrible).
 
 		Jerome
On a somewhat related note, I've often pondered writing a very limited D parser in CTFE to do this sort of thing more easily, but never got around to it, nevermind the CTFE memory bugs... -- Daniel
Jan 10 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:gk9v33$1bvu$1 digitalmars.com...
 Jérôme M. Berger wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Daniel Keep wrote:
 Michiel Helvensteijn wrote:
 [Condensed: syntax sucks, let's introduce more!]
I might be old fashioned (get offa mah lawn!), but I've always found something like the following quite acceptable: class Foo { mixin(properties (" rw int bar; ro float baz; wo Foo zyzzy; ")); }
Note that this is a very limited use for properties. Defining properties isn't just a question of access control (read/write, read only, or write only).
For me, it *was* a case of access-control... at least, it was about 80% of the time. I'm a fan of interface-heavy design: make an interface for every distinct kind of functionality and pack them all together. That means I end up with a metric buttload (equivalent to about 42 imperial piles) of properties. And most of them were just accessors that needed to be in the interface; hence the functionality of the mixin.
 It is also a way to execute arbitrary code
 each time the value is changed (or accessed), ...
It's been a while since I used the code, and honestly I can't seem to track it down, but I recall that I could do this: mixin(properties(" rw int bar; ")); protected void bar_onSet(int newValue) { ... } There was also an *_onGet, and you could block setting a property by throwing an exception, I believe. Granted, this doesn't cover every possible use-case, but then it's not supposed to; it's supposed to make the 90% easier. It still did the assignment, since I felt you shouldn't be making properties that have a setter that doesn't set anything...
 ... or to create
 properties that don't correspond to actual data fields (complex
 module and argument come to mind).
If the property doesn't correspond to a physical field, then you're going to have to write the code to handle it from scratch. And no matter WHAT you do, it's eventually going to boil down to one or more functions. Which is EXACTLY how they currently work. What would be the point of making a special syntax when you can already do that? :P
Same reason we have "while" and "foreach" in addition to "for".
 How would you do that with
 mixins? (Not that it would be impossible, but the syntax would
 probably be horrible).

 Jerome
On a somewhat related note, I've often pondered writing a very limited D parser in CTFE to do this sort of thing more easily, but never got around to it, nevermind the CTFE memory bugs... -- Daniel
Jan 10 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Nick Sabalausky wrote:
 "Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
 news:gk9v33$1bvu$1 digitalmars.com...
 [snip]
 
 What would be the point of making a special syntax when you can already do 
 that? :P
Same reason we have "while" and "foreach" in addition to "for".
How is this: property int foo { get { return compute_value(); } } Appreciably better than this: int foo() { return compute_value(); } We have for and foreach because iteration is a *very* common use for a loop, and you can screw it up when using while. In this case, having property syntax for a computed field doesn't buy you anything whatsoever apart from more typing. Yes, property syntax can simplify some cases, but this isn't one of them. -- Daniel P.S. Please don't get my hopes up by quoting my entire post and then only replying to one line; I thought I'd get to argue about my "80%" if nothing else. :P
Jan 10 2009
next sibling parent reply Miles <_______ _______.____> writes:
Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of them.
One good distinction properties and normal functions ought to make is that functions should never be called without (), and properties should never have () unless it has a function type. Current syntax allows crazy things like: ---------- exit = 1; // it is not an assignment x = toString = getenv = "PATH"; // creepy, but valid D if (fork == 1) // not comparing the value of a variable ---------- Also, currently, in D, if you have a property of a delegate type, you will have a mess. ---------- int func2() { return 42; } /* this is a property */ int function() prop() { return &func2; } void main() { auto x = prop; // ok, x is a func ptr auto y = prop(); // unexpected: y is not int :-( static assert (is(typeof(y) == int)); } ---------- With properties, you forbid the above syntaxes. So, what is "better" about properties is not shorter syntax, but giving proper semantics for a given symbol. Also, properties can be part of interfaces, enforcing derived classes to implement them in a given way.
Jan 10 2009
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Miles (_______ _______.____)'s article
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of them.
One good distinction properties and normal functions ought to make is that functions should never be called without ()
Why? This is really superfluous. I for one think that code is often more readable without the annoying empty parentheses around functions that don't take any arguments. This is especially true for member functions of classes and structs, even moreso when chaining them such as foo.bar.baz vs. foo().bar().baz().
 , and properties should
 never have () unless it has a function type.
 Current syntax allows crazy things like:
 ----------
 	exit = 1;	// it is not an assignment
 	x = toString = getenv = "PATH";	// creepy, but valid D
 	if (fork == 1)	// not comparing the value of a variable
 ----------
So? The spec is not there to prevent people from doing stupid things (making it harder to do stupid things *by accident* is a reasonable goal, but we're all consenting adults here). Anyone who would actually do stuff like this on purpose in their code is an idiot and deserves what they get. One could just as easily do some pretty stupid things with operator overloading, casts, templates, you name it. Just because stupid things *can* be done with a feature doesn't mean the feature should be removed.
 Also, currently, in D, if you have a property of a delegate type, you
 will have a mess.
 ----------
 	int func2() { return 42; }
 	/* this is a property */
 	int function() prop() {
 		return &func2;
 	}
 	void main() {
 		auto x = prop;		// ok, x is a func ptr
 		auto y = prop();	// unexpected: y is not int :-(
 		static assert (is(typeof(y) == int));
 	}
 ----------
 With properties, you forbid the above syntaxes.
 So, what is "better" about properties is not shorter syntax, but giving
 proper semantics for a given symbol.
Jan 10 2009
next sibling parent reply Miles <_______ _______.____> writes:
dsimcha wrote:
  I for one think that code is often more
 readable without the annoying empty parentheses around functions that don't
take
 any arguments.
It introduces ambiguities, and unexpected behavior, as I exemplified in the previous message. Parentheses (when following an identifier) has a precise meaning of calling the named function. That is something most modern procedural languages do, it is something programmers are used to. I see no advantage at giving the privilege to no-argument functions of being called without parentheses, while at the same time you lose the ability to distinguish between _calling_ the function from _referring_ to it.
 This is especially true for member functions of classes and
 structs,
Aren't these member functions good candidates to be made into real properties? If you want or need to use an identifier without parentheses, you have the option of making it into a property. Very simple.
 even moreso when chaining them such as foo.bar.baz vs. foo().bar().baz().
From your example, it appears that the purpose of foo and bar, and perhaps baz are to return instances, so they could just be turned into properties, and have the exact syntax you expect.
 So?  The spec is not there to prevent people from doing stupid things (making
it
 harder to do stupid things *by accident* is a reasonable goal, but we're all
 consenting adults here).  Anyone who would actually do stuff like this on
purpose
 in their code is an idiot and deserves what they get.  One could just as
easily do
 some pretty stupid things with operator overloading, casts, templates, you name
 it.  Just because stupid things *can* be done with a feature doesn't mean the
 feature should be removed.
You seem to be missing the point. In fact, you ignored the most important example in my previous message that shows how the current D's property syntax can be damaging. Also, your reasoning fails to take into account the difference between _allowing_ a certain syntax, and _incentivating_ bad usage.
Jan 10 2009
parent reply Bill Baxter <wbaxter gmail.com> writes:
On Sun, Jan 11, 2009 at 12:01 PM, Miles <_______ _______.____> wrote:
 dsimcha wrote:
  I for one think that code is often more
 readable without the annoying empty parentheses around functions that don't
take
 any arguments.
It introduces ambiguities, and unexpected behavior, as I exemplified in the previous message. Parentheses (when following an identifier) has a precise meaning of calling the named function. That is something most modern procedural languages do, it is something programmers are used to. I see no advantage at giving the privilege to no-argument functions of being called without parentheses, while at the same time you lose the ability to distinguish between _calling_ the function from _referring_ to it.
Not sure what you mean by that. It's just foo vs &foo in most cases. ...Except for some cases like where you're trying to return a delegate. I agree that 'except for' is not very pleasant.
 This is especially true for member functions of classes and
 structs,
Aren't these member functions good candidates to be made into real properties? If you want or need to use an identifier without parentheses, you have the option of making it into a property. Very simple.
He may want to retain the ability to pass it as a delegate to some other function too. If you make properties distinct from functions, then I don't think this can be allowed. So you'd need to have the property and a function that wraps the property. Then you've just made more work for yourself. Hmm, maybe properties should be allowed to be turned into delegates. --bb
Jan 10 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Bill Baxter" <wbaxter gmail.com> wrote in message 
news:mailman.378.1231643869.22690.digitalmars-d puremagic.com...
 On Sun, Jan 11, 2009 at 12:01 PM, Miles <_______ _______.____> wrote:
 dsimcha wrote:
  I for one think that code is often more
 readable without the annoying empty parentheses around functions that 
 don't take
 any arguments.
It introduces ambiguities, and unexpected behavior, as I exemplified in the previous message. Parentheses (when following an identifier) has a precise meaning of calling the named function. That is something most modern procedural languages do, it is something programmers are used to. I see no advantage at giving the privilege to no-argument functions of being called without parentheses, while at the same time you lose the ability to distinguish between _calling_ the function from _referring_ to it.
Not sure what you mean by that. It's just foo vs &foo in most cases. ...Except for some cases like where you're trying to return a delegate.
I'd consider those situations with delegates to be reason enough.
 I agree that 'except for' is not very pleasant.

 This is especially true for member functions of classes and
 structs,
Aren't these member functions good candidates to be made into real properties? If you want or need to use an identifier without parentheses, you have the option of making it into a property. Very simple.
He may want to retain the ability to pass it as a delegate to some other function too.
takesADelegate({ return foo.aProperty; }); takesADelegate((int newValue) { foo.aProperty = newValue }); Works with both variables and properties. Which is good, because the whole point of properties is to be used just like a variable. If you ever feel a need to use the property's actual setter or getter as a delegate, then something's been designed wrong. Also: void func(ref int x) {...} func(foo.aProperty); void func(int* x) {...} func(&foo.aProperty); *Should* work with both variables and properties (but might need some doesn't even bother with it.)
Jan 10 2009
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Nick Sabalausky wrote:
 void func(ref int x) {...}
 func(foo.aProperty);
 
 void func(int* x) {...}
 func(&foo.aProperty);
 
 *Should* work with both variables and properties (but might need some 

 doesn't even bother with it.)
That just can't work without radically changing what a pointer is. Disallowing pointers to properties is really the best fix. If you really wanted, you might be able to wrap a getter/setter pair into a struct and pass that instead (and have default getter/setter templates for non-properties). It's probably easier to just pass in getter/setter delegates explicitly though.
Jan 12 2009
parent "Nick Sabalausky" <a a.a> writes:
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message 
news:gkfmr2$1n9j$1 digitalmars.com...
 Nick Sabalausky wrote:
 void func(ref int x) {...}
 func(foo.aProperty);

 void func(int* x) {...}
 func(&foo.aProperty);

 *Should* work with both variables and properties (but might need some 

 just doesn't even bother with it.)
That just can't work without radically changing what a pointer is. Disallowing pointers to properties is really the best fix. If you really wanted, you might be able to wrap a getter/setter pair into a struct and pass that instead (and have default getter/setter templates for non-properties). It's probably easier to just pass in getter/setter delegates explicitly though.
What if properties were internally defined to be a struct of two delegates (and maybe the internal value)? Although that would still leave an issue of compatibility between int* and (property int)*, and might prevent the intrnal value from being optimized away...
Jan 12 2009
prev sibling parent reply Miles <_______ _______.____> writes:
Bill Baxter wrote:
 Not sure what you mean by that.  It's just  foo vs &foo in most cases.
 ...Except for some cases like where you're trying to return a delegate.
It is more tied with the intuitive use of symbols. 'foo' is a function, add a '&' before and you take its address, add a '(...)' after and you make a call and take its return value. The implicit call syntax without parentheses breaks this intuitive use. In fact, if you follow the principle of orthogonality, instead of calling the function without parameters, it would be much more sensible to have 'foo' return the function address, and deprecate the address operator. Then you could have functions and function/delegate pointers with similar semantics (principle of least surprise). --------- int func1() { return 1; } auto a = func1; // 'a' is a pointer to func1 auto b = &func1; // ERROR, or deprecated way of above auto c = func1(); // calls func1 and returns int 1 int function() func2 = func1; auto d = func2; // 'd' is a pointer to func1 auto e = &func2; // 'e' is a ptr to ptr to func auto f = func2(); // calls func1 and returns int 1 --------- Note that this way you have less surprises. Both func1 (the real function) and func2 (pointer to function) behave in similar ways. In current D, 'a' will be different than 'd', while 'c' will be equal to 'f'. The reasoning for deprecating &func1 is that func1 is not a variable, neither it is an lvalue. But now it is quite already too late to fix this, unless we go through a long period of deprecating the current behavior, until we can implement the new sane one.
 He may want to retain the ability to pass it as a delegate to some
 other function too.  If you make properties distinct from functions,
 then I don't think this can be allowed.
Yes, they are basically two distinct, mutually exclusive, compromises. A property is syntax sugar to a collection of delegates (all of them share the same scope). Properties are "views" that aim to behave as much as possible as variables. Optimally, you must ignore completely if a given symbol is a property or a variable. So, it makes little sense to pass a property as a delegate to a function. But it is still possible, and the solution actually keeps the fundamental property that variables and properties should be almost indistinguishable: ---------- int m_prop; property int prop { get() { return m_prop } set(int value) { m_prop = value; } } // lets say that func expects a setter func1( (int value){ prop = value; } ); // and func2 expects a getter func2( (){ return prop; } ); ---------- See? You passed delegates to the functions, and you kept the compromise that the code doesn't make distinction between properties and variables. The following code (taking the property out) is still valid: ---------- int prop; func1( (int value){ prop = value; } ); func2( (){ return prop; } ); ----------
 So you'd need to have the
 property and a function that wraps the property.
Exactly, or, instead of a function, an inline delegate is enough. As shown above, you win because then the code becomes insensitive to whether prop is a property or a variable.
 Then you've just made more work for yourself.
This is such a corner case that I think that using inline delegates is a good enough solution.
    Hmm, maybe properties should be
 allowed to be turned into delegates.
The compiler could provide a syntax for that. Like I said, a property is just a collection of delegates under a single identifier. For example, tentative syntax: ---------- property int prop { ... } auto setter = property(prop).set; // setter has type 'void delegate(int)' auto getter = property(prop).get; // getter has type 'int delegate()' ---------- But I think this is a secondary feature (if we keep demanding solutions for the corner cases, we will never have the solution for the biggest problem). I could live fine without this feature.
Jan 11 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Miles:
 In fact, if you follow the principle of orthogonality, instead of
 calling the function without parameters, it would be much more sensible
 to have 'foo' return the function address, and deprecate the address
 operator. Then you could have functions and function/delegate pointers
 with similar semantics (principle of least surprise).
I agree.
 But now it is quite already too late to fix this, unless we go through a
 long period of deprecating the current behavior, until we can implement
 the new sane one.
Seeing how much experimental D2 is, I think there's time to fix design bugs still. Bye, bearophile
Jan 11 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:gkd3b0$fkb$1 digitalmars.com...
 Miles:
 In fact, if you follow the principle of orthogonality, instead of
 calling the function without parameters, it would be much more sensible
 to have 'foo' return the function address, and deprecate the address
 operator. Then you could have functions and function/delegate pointers
 with similar semantics (principle of least surprise).
I agree.
 But now it is quite already too late to fix this, unless we go through a
 long period of deprecating the current behavior, until we can implement
 the new sane one.
Seeing how much experimental D2 is, I think there's time to fix design bugs still.
Even if it weren't for that, I would still consider this important enough to be worth the hassle of changing it. It would be better than letting D forever maintain the cruft of a particularly bad design decision (no offense, Walter) in the same way that C++ would.
Jan 11 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 Even if it weren't for that, I would still consider this important enough to 
 be worth the hassle of changing it. It would be better than letting D 
 forever maintain the cruft of a particularly bad design decision (no 
 offense, Walter) in the same way that C++ would.
But I am not sure that proposed idea is the best, because in Python (that acts like that) you often enough write for mistake: x = foo Forgetting the (). In this case x gets a (kind of) reference to foo and not to its result. You can do something similar in that D proposal: auto x = foo So I think &foo and foo() are more explicit and better (better == less error-prone), to represent the pointer/delegate/closure, and to represent the calling. Bye, bearophile
Jan 11 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:gkd53n$ikt$1 digitalmars.com...
 Nick Sabalausky:
 Even if it weren't for that, I would still consider this important enough 
 to
 be worth the hassle of changing it. It would be better than letting D
 forever maintain the cruft of a particularly bad design decision (no
 offense, Walter) in the same way that C++ would.
But I am not sure that proposed idea is the best, because in Python (that acts like that) you often enough write for mistake: x = foo Forgetting the (). In this case x gets a (kind of) reference to foo and not to its result. You can do something similar in that D proposal: auto x = foo So I think &foo and foo() are more explicit and better (better == less error-prone), to represent the pointer/delegate/closure, and to represent the calling.
Yes, but 1. As you indicated, it could only happen in D when using an initializer on an "auto". And 2. I would imagine that would probably get caught as soon x was used. But, if &foo is deemed to be better for referring to the function itself (ie without invoking), then using "foo" without "&" or "()" should be prohibited. (In fact, maybe that would be the ideal solution?)
Jan 11 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:
 Yes, but 1. As you indicated, it could only happen in D when using an 
 initializer on an "auto". And 2. I would imagine that would probably get 
 caught as soon x was used.
You are right, Python being dynamically typed the situation is a little worse there.
 then using "foo" without "&" or "()" should be 
 prohibited. (In fact, maybe that would be the ideal solution?)
That's what I was saying, to disallow "foo" without () or &. It's not the ideal situation but to me it looks better than the current ones (of both Python and D1). Bye, bearophile
Jan 11 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 11 Jan 2009 21:52:27 +0300, bearophile <bearophileHUGS lycos.com> wrote:

 Nick Sabalausky:
 Yes, but 1. As you indicated, it could only happen in D when using an
 initializer on an "auto". And 2. I would imagine that would probably get
 caught as soon x was used.
You are right, Python being dynamically typed the situation is a little worse there.
 then using "foo" without "&" or "()" should be
 prohibited. (In fact, maybe that would be the ideal solution?)
That's what I was saying, to disallow "foo" without () or &. It's not the ideal situation but to me it looks better than the current ones (of both Python and D1). Bye, bearophile
Yes, this is the best design so far. I'd also note that using foo without either "&" or "()" is still necessary to get access to foo's set of properties: auto s = foo.stringof; auto m = foo.mangleof; // etc Other than that I'm absolutely agree with both of you. Too bad language designers don't participate in the discussion.
Jan 11 2009
parent reply Sergey Kovrov <kovrov gmail.com> writes:
On 1/11/2009 9:32 PM, Denis Koroskin wrote:
 I'd also note that using foo without either "&" or "()" is still
 necessary to get access to foo's set of properties:

 auto s = foo.stringof;
 auto m = foo.mangleof;
 // etc
As far as I understand calling built-in properties eg. ``foo.stringof()`` is not allowed. And it is not an lvalue. So no referencing of a built-in properties possible either. I find this behavior most suitable for properties. The only exception is built-in ``.reverse`` and ``.sort`` properties which seems counter intuitive to me to be used without (). I think this should be something callable (built-in functions, inherited methods, etc.) rather than properties. -- serg.
Jan 11 2009
parent "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 12 Jan 2009 04:27:09 +0300, Sergey Kovrov <kovrov gmail.com> wrote:

 On 1/11/2009 9:32 PM, Denis Koroskin wrote:
 I'd also note that using foo without either "&" or "()" is still
 necessary to get access to foo's set of properties:

 auto s = foo.stringof;
 auto m = foo.mangleof;
 // etc
As far as I understand calling built-in properties eg. ``foo.stringof()`` is not allowed. And it is not an lvalue. So no referencing of a built-in properties possible either.
'&' and '()' were to be applied to foo rather that foo.property in the original message (i.e. &foo and foo()). I just provided example where neither '&' nor '()' were needed when accessing foo.
 I find this behavior most suitable for properties. The only exception is  
 built-in ``.reverse`` and ``.sort`` properties which seems counter  
 intuitive to me to be used without (). I think this should be something  
 callable (built-in functions, inherited methods, etc.) rather than  
 properties.

 -- serg.
Absolutely agree here.
Jan 11 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Miles wrote:
 ---------
 	int func1() { return 1; }
 
 	auto a = func1;		// 'a' is a pointer to func1
 	auto b = &func1;	// ERROR, or deprecated way of above
 	auto c = func1();	// calls func1 and returns int 1
 
 	int function() func2 = func1;
 
 	auto d = func2;		// 'd' is a pointer to func1
 	auto e = &func2;	// 'e' is a ptr to ptr to func
 	auto f = func2();	// calls func1 and returns int 1
 ---------
So you consider functions to be a reference type, since the value of a function is not terribly useful. You want the declarations "void foo() {}" and "invariant(void function()) foo = {};" to be equivalent. This can work, provided you get properties. Otherwise you're back to Javaland.
Jan 12 2009
parent Miles <_______ _______.____> writes:
Christopher Wright wrote:
 So you consider functions to be a reference type, since the value of a
 function is not terribly useful. You want the declarations "void foo()
 {}" and "invariant(void function()) foo = {};" to be equivalent.
Yes, almost equivalent.
Jan 13 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Sun, Jan 11, 2009 at 11:27 AM, dsimcha <dsimcha yahoo.com> wrote:
 == Quote from Miles (_______ _______.____)'s article
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of them.
One good distinction properties and normal functions ought to make is that functions should never be called without ()
Why? This is really superfluous. I for one think that code is often more readable without the annoying empty parentheses around functions that don't take any arguments. This is especially true for member functions of classes and structs, even moreso when chaining them such as foo.bar.baz vs. foo().bar().baz().
 , and properties should
 never have () unless it has a function type.
 Current syntax allows crazy things like:
 ----------
       exit = 1;       // it is not an assignment
       x = toString = getenv = "PATH"; // creepy, but valid D
       if (fork == 1)  // not comparing the value of a variable
 ----------
So? The spec is not there to prevent people from doing stupid things (making it harder to do stupid things *by accident* is a reasonable goal, but we're all consenting adults here). Anyone who would actually do stuff like this on purpose in their code is an idiot and deserves what they get. One could just as easily do some pretty stupid things with operator overloading, casts, templates, you name it. Just because stupid things *can* be done with a feature doesn't mean the feature should be removed.
I think the point is not that someone would do these things deliberately, it's that they might do them inadvertently. It's not that hard to end up with property names that sound like verbs or vice versa. Then the user of your code guesses that delay = true will be how to turn the 'delay' property on, and it compiles. But it turns out it it actually does a delay right then, and was really delay(bool yieldThread) or something like that, a parameterized action. All this just means one more thing you have to keep in mind while you're developing. You have to keep asking yourself "could somebody mistake this for a property?" every time you write a function with a short name. Or "could someone mistake this for an action?" when you think you're writing a property. Here's an issue I haven't seen discussed: What's the type of property foo? If a property can't be treated as a function, then it's type can't be the same as a function. It also can't be an int or whatever the referent type is. When you do __traits mojo and iterate over the members of the class, what should it return for a property? Not a killer I suppose, but there are probably more issues like that that would need to be dealt with that are more important than what the declaration syntax looks like. --bb
Jan 10 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Miles wrote:
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of them.
One good distinction properties and normal functions ought to make is that functions should never be called without (), and properties should never have () unless it has a function type. Current syntax allows crazy things like: ---------- exit = 1; // it is not an assignment x = toString = getenv = "PATH"; // creepy, but valid D if (fork == 1) // not comparing the value of a variable ----------
Walter and I see eye to eye that a possible solution would be to only allow the a = b syntax as an alternative for a(b) only if there's also a function a(). All of the above can be fixed within that framework.
 Also, currently, in D, if you have a property of a delegate type, you
 will have a mess.
 
 ----------
 	int func2() { return 42; }
 
 	/* this is a property */
 	int function() prop() {
 		return &func2;
 	}
 	
 	void main() {
 		auto x = prop;		// ok, x is a func ptr
 		auto y = prop();	// unexpected: y is not int :-(
 		static assert (is(typeof(y) == int));
 	}
 ----------
 
 With properties, you forbid the above syntaxes.
Well the above syntaxes could be forbidden other ways too. Andrei
Jan 10 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gkbtpo$1jq0$1 digitalmars.com...
 Miles wrote:
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of 
 them.
One good distinction properties and normal functions ought to make is that functions should never be called without (), and properties should never have () unless it has a function type. Current syntax allows crazy things like: ---------- exit = 1; // it is not an assignment x = toString = getenv = "PATH"; // creepy, but valid D if (fork == 1) // not comparing the value of a variable ----------
Walter and I see eye to eye that a possible solution would be to only allow the a = b syntax as an alternative for a(b) only if there's also a function a(). All of the above can be fixed within that framework.
I think that's a big part of the problem though. The current strategy just leads to various fringe cases with their own specialized "solutions". I think we have sufficient reason to consider "implicit properties" a failed experiment.
Jan 10 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 11 Jan 2009 07:50:03 +0300, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 Miles wrote:
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of  
 them.
One good distinction properties and normal functions ought to make is that functions should never be called without (), and properties should never have () unless it has a function type. Current syntax allows crazy things like: ---------- exit = 1; // it is not an assignment x = toString = getenv = "PATH"; // creepy, but valid D if (fork == 1) // not comparing the value of a variable ----------
Walter and I see eye to eye that a possible solution would be to only allow the a = b syntax as an alternative for a(b) only if there's also a function a(). All of the above can be fixed within that framework.
It was criticized many times by different people as being a too complex and obscure rule. First, you allow to omit empty pair of braces. Now you understand that it was a bad idea as it bring to many problems and ambiguities. But instead of /fixing/ the source of the issues, you are trying to /reduce/ number of those issues (by narrowing range of cases where omitting parens allowed). That's a wrong way to go. You can reduce them, but you can't eliminate them entirely this way. It doesn't allow authors to define what is callable with property syntax and what is not. For example, I know many people that never use default function arguments because they cause too many problems with inheritance (some of them come from languages that doesn't allow them at all). Instead, the define two distinct functions: class Foo { int bar(int i) { // do something more intelligent here return i; } int bar() { // call main function with default arguments. // Default arguments may be overridden in derived class. return bar(42); } } And a Pandora's Box is open: Foo foo = new Foo(); foo.bar = -1; One more case - properties can not return references: class Foo { ref int bar() { return _bar; } private int _bar; } Foo foo = new Foo(); foo.bar = -1; test.d(17): function test.Foo.bar () does not match parameter types (int) test.d(17): Error: expected 0 arguments, not 1 Nevertheless, let's assume it is a bug and it will be fixed (one more case where optional parens feature causes a compiler bug). Then, what does the following code do: class Foo { ref int bar() { return _bar; } void bar(int i) { _bar = i; } private int _bar; } Foo foo = new Foo(); foo.bar = -1; // which one of the functions is called? Both are suitable. Compare it with the following one: class Foo { void bar(int i = 0) {} void bar() {} } Foo foo = new Foo(); foo.bar(); // which one is called? DMC result for reference: a.foo(); ^ test.cpp(20) : Error: ambiguous reference to symbol Had: A::foo() and: A::foo(int ) Besides, it has nothing to do with issue below:
 Also, currently, in D, if you have a property of a delegate type, you
 will have a mess.
  ----------
 	int func2() { return 42; }
  	/* this is a property */
 	int function() prop() {
 		return &func2;
 	}
 	
 	void main() {
 		auto x = prop;		// ok, x is a func ptr
 		auto y = prop();	// unexpected: y is not int :-(
 		static assert (is(typeof(y) == int));
 	}
 ----------
  With properties, you forbid the above syntaxes.
Well the above syntaxes could be forbidden other ways too. Andrei
They should not be forbidden, they should be allowed! Imagine a struct that emulates virtual behavior with methods as first-class objects: struct Message { string text; void delegate() show() // property getter { return _showDg; } void show(void delegate(ref Message message) dg) // property setter { _showDg = () { dg(this); } } private void delegate() _showDg; } auto showDg1 = (ref Message msg) { writefln(msg.text); } // output to stdout auto showDg2 = (ref Message msg) { MessageBox(0, "Message", msg.text, 0); } // show a message box Message message; message.text = "Hello World"; message.show = showDg1; message.show()(); // works but requires two pair of braces message.show = showDg2; message.show(); // this is a goal How would you /allow/ that? Why don't you see that non-mandatory parens bring more troubles than it /tries/ to solve.
Jan 10 2009
prev sibling next sibling parent Miles <_______ _______.____> writes:
Andrei Alexandrescu wrote:
 Walter and I see eye to eye that a possible solution would be to only
 allow the a = b syntax as an alternative for a(b) only if there's also a
 function a(). All of the above can be fixed within that framework.
That would only patch a single consequence of the much bigger core problem that is the current property syntax. Not to say that, although rare, it is perfectly possible to have write-only properties. I once wrote a microcontroller emulator that had a few write-only registers, serial port output, for example.
Jan 11 2009
prev sibling parent reply =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andrei Alexandrescu wrote:
 Miles wrote:
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of
 them.
One good distinction properties and normal functions ought to make is that functions should never be called without (), and properties should never have () unless it has a function type. Current syntax allows crazy things like: ---------- exit = 1; // it is not an assignment x = toString = getenv = "PATH"; // creepy, but valid D if (fork == 1) // not comparing the value of a variable ----------
Walter and I see eye to eye that a possible solution would be to only allow the a = b syntax as an alternative for a(b) only if there's also a function a(). All of the above can be fixed within that framework.
Won't work: how do you then create a write-only property? Jerome - -- mailto:jeberger free.fr http://jeberger.free.fr Jabber: jeberger jabber.fr -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAklqQ3cACgkQd0kWM4JG3k8TCACdG8B16tlHlJJuv5ct7gegvog3 HuAAmwb/ooNnVrtpkLIh7u/I3uUwpqXK =+nhK -----END PGP SIGNATURE-----
Jan 11 2009
parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Jan 12, 2009 at 4:07 AM, "J=E9r=F4me M. Berger" <jeberger free.fr> =
wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Andrei Alexandrescu wrote:
 Miles wrote:
 Daniel Keep wrote:
 Yes, property syntax can simplify some cases, but this isn't one of
 them.
One good distinction properties and normal functions ought to make is that functions should never be called without (), and properties should never have () unless it has a function type. Current syntax allows crazy things like: ---------- exit =3D 1; // it is not an assignment x =3D toString =3D getenv =3D "PATH"; // creepy, but valid D if (fork =3D=3D 1) // not comparing the value of a variable ----------
Walter and I see eye to eye that a possible solution would be to only allow the a =3D b syntax as an alternative for a(b) only if there's also=
a
 function a(). All of the above can be fixed within that framework.
Won't work: how do you then create a write-only property?
I'm guessing they thought of that and the answer is you can't, but write-only properties are a rare corner case. But either way, it doesn't solve the ambiguity problem. A callback setter/getter pair will still run into trouble because you can't tell if the getter wants to get the callback or actually call it. --bb
Jan 11 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Miles" <_______ _______.____> wrote in message 
news:gkbk5p$14gr$1 digitalmars.com...
 So, what is "better" about properties is not shorter syntax, but giving
 proper semantics for a given symbol.
I'd say the point of properties is both a matter of clean implementation syntax and proper calling semantics/syntax. In the case of the calling semantics/syntax, I see it as essentially boiling down to an issue of "nouns vs verbs" and proper abstraction. The way I see it: Variables are the programming world's nouns, and functions are the programming world's verbs. Objects (nouns) have attributes (nouns) and are capable of doing things (verbs). Thus, things that are noun-like and can be thought of as an attribute of an object should be accessed using noun/variable syntax (this means no parentheses), and things that are conceptualized as actions the object can perform should be invoked using verb/function syntax (this means parentheses). Although if you're merely *referring* to a verb/function (as in the phrase "the act of walking"), then you're using the verb as a noun and should refer to the verb with the standard noun syntax (no parens). Example of proper design strategy: We want to programmatically represent the noun of "color". First thing we need is a type. There's no built-in, so we need to define a custom type, a class. Next thing we need is a list of attributes and actions associated with "color": Actions (things color can do): Color isn't a physical object so there's not much it can actually do: - Inspire an Artist (Artist being the grammatical "direct object", and therefore the parameter) Attributes (things color has): - Hue - Saturation - Brightness/Darkness - Red component - Green component - Blue component - Yellow component - Cyan component - Magenta component - Transparency/Opaqueness - Shininess - etc... Now to translate into (psuedo)code: void inspire(Artist artist) { /* magic code here */ } val hue; val saturation; val blackness; val red; val green; val blue; val yellow; val cyan; val magenta; val transparency val shininess; ("val", of course, being a type representing the range of "max".."min") Now at this point any sane programmer would see the redundancy (and potential for invalid, self-contradicting state) in storing HSV, RGB, *and* CMYK. They'd then probably choose a single internal format (we'll say RGB), and decide to calculate all of the redundant attributes from that. This is good design. But here's the part where many people go wrong. They say "Since I'm calculating HSVCM and Y, that means 'function'" (And yes, it does mean "function", but only on the *implementation* side.) Then they do something like this: val getHue(); val getSaturation(); val getBlackness(); val red; // Might be changed to getRed() for consistency val green; val blue; val getYellow(); val getCyan(); val getMagenta(); Bad programmer! Bad, bad, bad programmer! Hue and Yellow aren't actions of color, they're attributes! Nouns, nouns, nouns! Turning them into verbs by sticking "get" in front just made a bastardized mockery out of high-level-language abstraction. Not only that but the implementation detail of "some of these are calculated instead of stored internally" has leaked out into the interface and slapped the idea of encapsulation in the face. At this point, D comes in and tries to solve the problem with omittable parens on functions. But that puts the onus on the caller. So what, the caller is now supposed to be defining the interface? That's dumb because the author of the class has already decided whether a particular member is a noun or a verb by naming it "red" instead of "getRed" or vice versa. If you've got something like "red component" that is conceptually understood as a noun, it should be accessed with noun syntax. Call it "good redundancy" (*nudge* *nudge* Walter?). Whether or not the class author decides to *implement* it as a computation or a simple memory access should not impact accessing it. As it is now, whenever a conceptual attribute is switched between variable and "property", the legality of sticking () on the end of it flip-flops. How is that desirable behavior?
Jan 10 2009
next sibling parent Michiel Helvensteijn <nomail please.com> writes:
Nick Sabalausky wrote:

 <Great Example>
Hear, hear! -- Michiel
Jan 11 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:gkbuap$1khp$1 digitalmars.com...
 Objects (nouns) have attributes (nouns) and are capable of doing things 
 (verbs).
That should probably be: Objects (nouns) have attributes (adjectives/nouns) and are capable of doing things (verbs). But, of course, adjectives (just like "direct/indirect objects") are themselves nouns.
Jan 11 2009
parent reply John Reimer <terminal.node gmail.com> writes:
Hello Nick,

 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
 
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Jan 11 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"John Reimer" <terminal.node gmail.com> wrote in message 
news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 Hello Nick,

 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
Jan 11 2009
next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Sun, Jan 11, 2009 at 11:02 PM, Nick Sabalausky <a a.a> wrote:
 Maybe there's examples I'm not thinking of, and I'm certainly no natural
 language expert, but consider these:

 "red"
 "ball"
 "red ball"

 By themselves, "red" and "ball" are both nouns. Stick the noun "red" in
 front of ball and "red" becomes an adjectve. (FWIW,
 "dictionary.reference.com" lists "red" as both a noun and an adjective). The
 only adjectives I can think of at the moment (in my admittedly quite tired
 state) are words that are ordinarly nouns on their own.  I would think that
 the distinguishing charactaristic of an adjective vs noun would be the
 context in which it's used.

 Maybe I am mixed up though, it's not really an area of expertise for me.
That "red" can be used as both a noun and as an adjective is just a coincidence. Well, it's not entirely coincidental - there are many adjectives which have been nominalized like this. Some other languages (like Spanish) allow you to use an adjective as a noun, in which case it's like saying "<adjective> one" i.e. "el gordo" = "the fat [one]". In English, though, that process is far from productive. Consider the adjectives "sleepy", "hard", or "loud". There are of course nominalized forms of these - sleepiness, hardness, loudness - but they're separate words.
Jan 11 2009
prev sibling next sibling parent reply John Reimer <terminal.node gmail.com> writes:
Hello Nick,

 "John Reimer" <terminal.node gmail.com> wrote in message
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 
 Hello Nick,
 
 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
 
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
No problem. I am not saying a word can't be /used/ as an adjective and noun in different contexts. I'm just saying that they can't be an adjective and noun at the same time as your first post suggested. Grammatically, adjectives are not nouns (ever), even if the words themselves can be used as either in independent contexts; they just modify nouns. Like Jarett mentions, the fact that words that are adjectives in one context can shapeshift to another part of speech (the noun) in another, is immaterial to the definition: you just have to recognize when it happens and realize the change that has occurred in the part of speech. It something like how D uses the "!" prefix to instantiate a template and in another context uses it as a logical NOT. They can't mean both at the same time. They mean something different depending on where they are used. -JJR
Jan 11 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"John Reimer" <terminal.node gmail.com> wrote in message 
news:28b70f8c119bd8cb4246de86cc80 news.digitalmars.com...
 Hello Nick,

 "John Reimer" <terminal.node gmail.com> wrote in message
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...

 Hello Nick,

 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
No problem. I am not saying a word can't be /used/ as an adjective and noun in different contexts. I'm just saying that they can't be an adjective and noun at the same time as your first post suggested. Grammatically, adjectives are not nouns (ever), even if the words themselves can be used as either in independent contexts; they just modify nouns. Like Jarett mentions, the fact that words that are adjectives in one context can shapeshift to another part of speech (the noun) in another, is immaterial to the definition: you just have to recognize when it happens and realize the change that has occurred in the part of speech.
I guess that's a difference between natural languages and oop-languages then. A member variable of an object typically /describes an attribute/ of the object, and thus makes it comparable to the notion of "adjective", but in an oop-language (and apperently unlike a natural language) that member object is itself either another object or a primitive.
 It something like how D uses the "!" prefix to instantiate a template and 
 in another context uses it as a logical NOT.  They can't mean both at the 
 same time.  They mean something different depending on where they are 
 used.
Ok, I see what you're saying.
Jan 12 2009
parent John Reimer <terminal.node gmail.com> writes:
Hello Nick,

 "John Reimer" <terminal.node gmail.com> wrote in message
 news:28b70f8c119bd8cb4246de86cc80 news.digitalmars.com...
 
 Hello Nick,
 
 "John Reimer" <terminal.node gmail.com> wrote in message
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 
 Hello Nick,
 
 But, of course, adjectives (just like "direct/indirect objects")
 are themselves nouns.
 
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
No problem. I am not saying a word can't be /used/ as an adjective and noun in different contexts. I'm just saying that they can't be an adjective and noun at the same time as your first post suggested. Grammatically, adjectives are not nouns (ever), even if the words themselves can be used as either in independent contexts; they just modify nouns. Like Jarett mentions, the fact that words that are adjectives in one context can shapeshift to another part of speech (the noun) in another, is immaterial to the definition: you just have to recognize when it happens and realize the change that has occurred in the part of speech.
I guess that's a difference between natural languages and oop-languages then. A member variable of an object typically /describes an attribute/ of the object, and thus makes it comparable to the notion of "adjective", but in an oop-language (and apperently unlike a natural language) that member object is itself either another object or a primitive.
Yes, although natural languages and programming languages might share some similarities, natural langauges are going to be much more complex (even though both consist of grammars and alphabets). I know there's a whole science and theory of natural language analysis of which I'm mostly ignorant beyond a basic introduction. Much of the research of computer languages and compilers seems to have borrowed from the study of natural languages (see Noam Chomsky). I need to study it more myself. Also I just want to make clear that my explanation above was meant only to emphasize English grammar rules. I don't know enough about other natural langauges to make the statement universally applicable. There are some very "unusual" natural languages out there that will have a very different grammar such that, I suppose, they would seem to break the rules familiar to an English speaker. But, of course, a different language is not subject to the rules of the English grammar, so it should be no surprise. -JJR
Jan 12 2009
prev sibling parent reply Benji Smith <dlanguage benjismith.net> writes:
Nick Sabalausky wrote:
 "John Reimer" <terminal.node gmail.com> wrote in message 
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 Hello Nick,

 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
Incidentally... I used to do a lot of work in natural language processing, and our parsing heuristics were built to handle a lot of adjective/noun ambiguity. For example, in the phrase "car dealership", the word "car" is an adjective that modifies "dealership". For the most part, you can treat adjectives and nouns as being functionally identical, and the final word in a sequence of adjectives and nouns becomes the primary noun of the noun-phrase. --benji
Jan 12 2009
next sibling parent John Reimer <terminal.node gmail.com> writes:
Hello Benji,

 Nick Sabalausky wrote:
 
 "John Reimer" <terminal.node gmail.com> wrote in message
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 
 Hello Nick,
 
 But, of course, adjectives (just like "direct/indirect objects")
 are themselves nouns.
 
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
Incidentally... I used to do a lot of work in natural language processing, and our parsing heuristics were built to handle a lot of adjective/noun ambiguity. For example, in the phrase "car dealership", the word "car" is an adjective that modifies "dealership". For the most part, you can treat adjectives and nouns as being functionally identical, and the final word in a sequence of adjectives and nouns becomes the primary noun of the noun-phrase. --benji
Interesting. There is certainly room to play here. I never thought of this potential ambiguity of "nouns" and "adjectives" in a noun phrase. Thanks for the info. I'll look into this a little more. I guess Nick wasn't /that/ far of track. :) -JJR
Jan 12 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Benji Smith wrote:
 Nick Sabalausky wrote:
 "John Reimer" <terminal.node gmail.com> wrote in message 
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 Hello Nick,

 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
Incidentally... I used to do a lot of work in natural language processing, and our parsing heuristics were built to handle a lot of adjective/noun ambiguity. For example, in the phrase "car dealership", the word "car" is an adjective that modifies "dealership".
It's a genitive phrase, not an adjective. You couldn't say "That dealership is car", for instance, but you could say "That is a dealership of cars."
 For the most part, you can treat adjectives and nouns as being 
 functionally identical, and the final word in a sequence of adjectives 
 and nouns becomes the primary noun of the noun-phrase.
No, you can't: "I gave the postman chlamydia." What is postman chlamydia?
 --benji
Jan 13 2009
parent John Reimer <terminal.node gmail.com> writes:
Hello Christopher,

 Benji Smith wrote:
 
 Nick Sabalausky wrote:
 
 "John Reimer" <terminal.node gmail.com> wrote in message
 news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...
 
 Hello Nick,
 
 But, of course, adjectives (just like "direct/indirect objects")
 are themselves nouns.
 
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
Maybe there's examples I'm not thinking of, and I'm certainly no natural language expert, but consider these: "red" "ball" "red ball" By themselves, "red" and "ball" are both nouns. Stick the noun "red" in front of ball and "red" becomes an adjectve. (FWIW, "dictionary.reference.com" lists "red" as both a noun and an adjective). The only adjectives I can think of at the moment (in my admittedly quite tired state) are words that are ordinarly nouns on their own. I would think that the distinguishing charactaristic of an adjective vs noun would be the context in which it's used. Maybe I am mixed up though, it's not really an area of expertise for me.
Incidentally... I used to do a lot of work in natural language processing, and our parsing heuristics were built to handle a lot of adjective/noun ambiguity. For example, in the phrase "car dealership", the word "car" is an adjective that modifies "dealership".
It's a genitive phrase, not an adjective. You couldn't say "That dealership is car", for instance, but you could say "That is a dealership of cars."
 For the most part, you can treat adjectives and nouns as being
 functionally identical, and the final word in a sequence of
 adjectives and nouns becomes the primary noun of the noun-phrase.
 
No, you can't: "I gave the postman chlamydia." What is postman chlamydia?
 --benji
 
The reason I conceeded a little on this one is because of http://en.wikipedia.org/wiki/Noun_phrase. I'm not sure if wikipedia can be absolutely trusted... but this is beyond my grammatical knowledge to argue absolutely. In a sentence diagram, I would assume that adjectives would have to be distinctly positioned. In Benji's example, I assume practicality of implementation is what allows adjectives/nouns to be treated similarly, not necessarily strict adherence to grammatical rules. Just guessing... -JJR
Jan 13 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
John Reimer wrote:
 Hello Nick,
 
 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
No programming language that I know distinguishes parts of an object (the hand of a body) from attributes of an object (the color of a ball). I think that's what he was getting at.
Jan 12 2009
parent John Reimer <terminal.node gmail.com> writes:
Hello Christopher,

 John Reimer wrote:
 
 Hello Nick,
 
 But, of course, adjectives (just like "direct/indirect objects") are
 themselves nouns.
 
Umm... May I make a little correction here? Adjectives are not nouns. They are used to /describe/ nouns. -JJR
No programming language that I know distinguishes parts of an object (the hand of a body) from attributes of an object (the color of a ball). I think that's what he was getting at.
Yes, I was not critiquing his commentary on programming languages: it would have been dangerous for me to do so :). I was being (perhaps overly) nit-picky about his statement that incorrectly paralleled English grammar to the topic of discussion. -JJR
Jan 12 2009
prev sibling parent reply dsimcha <dsimcha yahoo.com> writes:
I'm starting to think that this properties thing is becoming a hopelessly
complicated solution to a very simple problem.  The issue that brought this to a
head in the first place was foo = foo + 1 vs. foo += 1.  Given that solving this
case properly seems like a rather difficult problem, the solution of just
defining
foo += 1 to mean foo = foo + 1 (which is what was originally proposed before
issues about properties of user-defined types were brought up) is starting to
look
appealing.  Yes, this might be inefficient on user defined types w/ operator
overloading, but so is the equivalent in other languages:

SomeObject temp = myClass.getFoo();
myClass.setFoo(temp + 1);

I figure the vast majority of cases are going to be primitive types anyhow
(mostly
ints), and if someone defines operator overloads such that foo += 1 produces
totally different observable behavior than foo = foo + 1, that's just too
ridiculously bad a design to even take seriously.  What do you think?  Is it
worth
ignoring a few hard cases in exchange for solving most cases simply and
elegantly
and without adding any new constructs?
Jan 10 2009
next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Sun, Jan 11, 2009 at 12:52 PM, dsimcha <dsimcha yahoo.com> wrote:
 I'm starting to think that this properties thing is becoming a hopelessly
 complicated solution to a very simple problem.  The issue that brought this to
a
 head in the first place was foo = foo + 1 vs. foo += 1.  Given that solving
this
 case properly seems like a rather difficult problem, the solution of just
defining
 foo += 1 to mean foo = foo + 1 (which is what was originally proposed before
 issues about properties of user-defined types were brought up) is starting to
look
 appealing.  Yes, this might be inefficient on user defined types w/ operator
 overloading, but so is the equivalent in other languages:

 SomeObject temp = myClass.getFoo();
 myClass.setFoo(temp + 1);

 I figure the vast majority of cases are going to be primitive types anyhow
(mostly
 ints), and if someone defines operator overloads such that foo += 1 produces
 totally different observable behavior than foo = foo + 1, that's just too
 ridiculously bad a design to even take seriously.  What do you think?  Is it
worth
 ignoring a few hard cases in exchange for solving most cases simply and
elegantly
 and without adding any new constructs?
Well, foo+=1 is not the only issue. It may have been the one that brought it to a head this time, but the issue has come up in the past with the focus on fixing the ambiguities around allowing functions to be called without (). Mainly I think that ambiguity relates to properties that return callable things. If foo is such a property then it's not clear how to call the thing returned by foo. I think the only way to make such things make sense and be consistent is to disallow the implicit function call stuff. --bb
Jan 10 2009
prev sibling next sibling parent Chad J <gamerchad __spam.is.bad__gmail.com> writes:
dsimcha wrote:
 I'm starting to think that this properties thing is becoming a hopelessly
 complicated solution to a very simple problem.  The issue that brought this to
a
 head in the first place was foo = foo + 1 vs. foo += 1.  Given that solving
this
 case properly seems like a rather difficult problem, the solution of just
defining
 foo += 1 to mean foo = foo + 1 (which is what was originally proposed before
 issues about properties of user-defined types were brought up) is starting to
look
 appealing.  Yes, this might be inefficient on user defined types w/ operator
 overloading, but so is the equivalent in other languages:
 
 SomeObject temp = myClass.getFoo();
 myClass.setFoo(temp + 1);
 
 I figure the vast majority of cases are going to be primitive types anyhow
(mostly
 ints), and if someone defines operator overloads such that foo += 1 produces
 totally different observable behavior than foo = foo + 1, that's just too
 ridiculously bad a design to even take seriously.  What do you think?  Is it
worth
 ignoring a few hard cases in exchange for solving most cases simply and
elegantly
 and without adding any new constructs?
foo = foo + 1 vs foo += 1 is not the only issue here. Indeed, it is rather one of the less important ones, since it tends to give you a compile error instead of sending you on hours of debugging. Bill already mentioned that properties returning callable things were a problem. There's another one too: import tango.io.Stdout; struct Foo { char[] a = "Waait, something's wrong here."; } class Bar { Foo m_foo; Foo foo() { return m_foo; } // Interestingly, write properties are completely optional // when writing this kind of bug. // Foo foo( Foo value ) { return m_foo = value; } } void main() { auto b = new Bar(); b.foo.a = "Everything is fine."; Stdout( b.foo.a ).newline; //Prints "Waait, something's wrong here" // or writefln( b.foo.a ); if you prefer. } try it out (D1 code). This demonstrates how easy it is to write broken properties. It is related to foo = foo + 1 vs foo += 1 in that returning lvalues might solve both of these. However, as was mentioned before properties are not lvalues, so making properties always return lvalues may very well make more trouble for us.
Jan 10 2009
prev sibling parent reply Miles <_______ _______.____> writes:
dsimcha wrote:
 I figure the vast majority of cases are going to be primitive types anyhow
(mostly
 ints),
Yes, this is very true.
 and if someone defines operator overloads such that foo += 1 produces
 totally different observable behavior than foo = foo + 1, that's just too
 ridiculously bad a design to even take seriously.
Sure. It is bad coding style, it is ugly and the programmer who does this should be called for a meeting with his boss. But there are still ways to have sane behavior, even in such situations. See below.
 What do you think?  Is it worth
 ignoring a few hard cases in exchange for solving most cases simply and
elegantly
 and without adding any new constructs?
Instead, I think it is more sane to use temporaries. ---------- { auto tmp = __get_foo(); tmp += 1; __set_foo(foo); } ---------- It is the safest this way, principle of least surprise. If the caller does foo += 1, it will get that; if it does foo = foo + 1, it will still get that; if it does foo.call(), again, the behavior is still sane. We must first attack the semantics. This have sane semantics. Then let the compiler optimize that as far as possible. The compiler inlines the getter and setter calls, then optimizes away the temporary, etc.
Jan 11 2009
parent Benji Smith <dlanguage benjismith.net> writes:
Miles wrote:
 dsimcha wrote:
 I figure the vast majority of cases are going to be primitive types anyhow
(mostly
 ints),
Yes, this is very true.
 and if someone defines operator overloads such that foo += 1 produces
 totally different observable behavior than foo = foo + 1, that's just too
 ridiculously bad a design to even take seriously.
Sure. It is bad coding style, it is ugly and the programmer who does this should be called for a meeting with his boss. But there are still ways to have sane behavior, even in such situations. See below.
 What do you think?  Is it worth
 ignoring a few hard cases in exchange for solving most cases simply and
elegantly
 and without adding any new constructs?
Instead, I think it is more sane to use temporaries. ---------- { auto tmp = __get_foo(); tmp += 1; __set_foo(foo); } ---------- It is the safest this way, principle of least surprise. If the caller does foo += 1, it will get that; if it does foo = foo + 1, it will still get that; if it does foo.call(), again, the behavior is still sane. We must first attack the semantics. This have sane semantics. Then let the compiler optimize that as far as possible. The compiler inlines the getter and setter calls, then optimizes away the temporary, etc.
Or the compiler could prevent properties from returning mutable structs? class MyClass { private MyStruct _a; private MyStruct _b; public property a { const get { return _a; } // legal } public property a { get { return _b; } // compile-time error } } On the flip-side, the compiler could intervene at the call site, preventing modification of structs when directly accessed via a property invocation. Though I think the first solution is better. --benji
Jan 12 2009
prev sibling parent Don <nospam nospam.com> writes:
dsimcha wrote:
 == Quote from BCS (ao pathlink.com)'s article
 Reply to Vishaal,
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
Yeah, this has been mentioned in the past before. The most obvious way to make it work w/o any breaking or significantly bulk-adding changes would be to define foo.length += 8 to mean foo = foo.length() + 8, or foo.length++ mean foo = foo.length + 1. This would be pure syntactic sugar, as it is when working with primitives. One problem that comes to mind is if, instead of length, which is presumably some kind of integer, you have a property for some user defined type with operator overloading. This user-defined type could define opAdd to do something arbitrarily different from opAddAssign. Even if we assume that no reasonable programmer would do this and treat this as a "who cares?" corner case,
It was recently pointed out in another thread that if prop is a class, it is currently nearly IMPOSSIBLE for prop += 8; to be the same as prop = prop + 8;. Properties therefore seem to be another important reason for fixing up operator overloading. there's
 still the problem of opInc and opAddAssign being much cheaper in some cases
than
 opAdd.  For example, in some cases opAdd might require copying of a whole
bunch of
 stuff, where opInc or opAddAssign just increments a single primitive under the
hood.
 
 Bottom line is, unless we assume that properties of user-defined types aren't
 important, we need a better solution.  Oh yeah, and on the more special case of
 arrays, which the compiler already treats as special, yes, foo.length += 2
should
 be legal.  As far as I can tell, this is a no-brainer.
Jan 08 2009
prev sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
BCS wrote:
 Reply to Vishaal,
 
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
Gripe gripe gripe gripe gripe
Jan 07 2009
parent reply =?UTF-8?B?QWxleGFuZGVyIFDDoW5law==?= writes:
Ellery Newcomer wrote:
 BCS wrote:
 Reply to Vishaal,

 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I think there is a (long standing) bug report about that one. Maybe if enough people gripe about it it will get fixed! (NOT said sarcastically!)
Gripe gripe gripe gripe gripe
Guriiiiipe. Gripe gripe. GRIPE.
Jan 07 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Alexander Pánek:
 Guriiiiipe. Gripe gripe. GRIPE.
Is this the second (redundant) system to vote for the most hated bugs? Bye, bearophile
Jan 08 2009
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
bearophile wrote:
 Alexander Pánek:
 Guriiiiipe. Gripe gripe. GRIPE.
Is this the second (redundant) system to vote for the most hated bugs? Bye, bearophile
Maybe we need a bot to monitor bugs' GPS [1]. You can never have too many redundant systems, afterall! -- Daniel P.S. Gripe gripe, gr-gr-gripe, GRIPE! [1] Gripes Per Second.
Jan 08 2009
prev sibling parent Mike James <foo bar.com> writes:
<fx chanting vikings in background>
Gripe, Gripe, Gripe. Gripe, Gripe, Gripe, Wonderful Gripe...

</fx>
Jan 08 2009
prev sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 08 Jan 2009 03:45:08 +0300, Vishaal <vishaal nospam.com> wrote:

 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I'd like to point out another related issue that everyone seems to miss. The following code is taken from a GUI library: struct Rect { int x, y, width, height; void reset() { x = y = width = height = 0; } } class Control { //... Rect rect() { return _rect; } void rect(Rect newRect) { _resizeControl(newRect); } void _resizeControl(Rect rect) { // ... } private Rect _rect; //... } Imagine rect is not a property but a field, first. How would you mutate it? I'd do it as follows: Control c = new Control(); c.rect.reset(); c.rect.width = 100; Both lines do nothing when field replaced with a property. Code is broken but there is no complains from compiler. You should write the following code instead: Control c = new Control(); auto tmp = c.rect; tmp.reset(); c.rect = tmp; auto tmp = c.rect; tmp.width = 100; c.rect = tmp; but it doesn't look good. Compiler could be smarter in this regard - it could generate the code above automatically whenever a mutating method is called on a property. And here is also another issue I can't wait to be fixed. The following syntax: auto prop = foo.prop(); works for properties but not for fields, meaning that whenever code author decides to change it from property to field, user code is broken. Properties should not have optional braces! As a result, properties and fields can not be used interchangeably until issues above are fixed.
Jan 10 2009
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Denis Koroskin wrote:
 On Thu, 08 Jan 2009 03:45:08 +0300, Vishaal <vishaal nospam.com> wrote:
 
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I'd like to point out another related issue that everyone seems to miss.
<snip struct example> result, we have some types that could easily be POD structs but are classes instead. On the other hand, gmcs (the Mono compiler) errors out when you try modifying a struct that you access by a property, and the Microsoft compiler probably does as well: struct_prop.cs(24,21): error CS1612: Cannot modify a value type return value of `Foo.bar'. Consider storing the value in a temporary variable struct_prop.cs(3,8): (Location of the symbol related to previous error) struct_prop.cs(24,21): error CS0200: Property or indexer `Foo.bar' cannot be assigned to (it is read only) Compilation failed: 2 error(s), 0 warnings
Jan 11 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Thu, 08 Jan 2009 03:45:08 +0300, Vishaal <vishaal nospam.com> wrote:
 
 Properties, such as array.length, should return lvalues to allow:
 a.length += 8;
 or other similar statements.
I'd like to point out another related issue that everyone seems to miss. The following code is taken from a GUI library: struct Rect { int x, y, width, height; void reset() { x = y = width = height = 0; } } class Control { //... Rect rect() { return _rect; } void rect(Rect newRect) { _resizeControl(newRect); } void _resizeControl(Rect rect) { // ... } private Rect _rect; //... } Imagine rect is not a property but a field, first. How would you mutate it? I'd do it as follows: Control c = new Control(); c.rect.reset(); c.rect.width = 100; Both lines do nothing when field replaced with a property. Code is broken but there is no complains from compiler. You should write the following code instead: Control c = new Control(); auto tmp = c.rect; tmp.reset(); c.rect = tmp; auto tmp = c.rect; tmp.width = 100; c.rect = tmp; but it doesn't look good. Compiler could be smarter in this regard - it could generate the code above automatically whenever a mutating method is called on a property. And here is also another issue I can't wait to be fixed. The following syntax: auto prop = foo.prop(); works for properties but not for fields, meaning that whenever code author decides to change it from property to field, user code is broken. Properties should not have optional braces! As a result, properties and fields can not be used interchangeably until issues above are fixed.
This is a very strong argument. The issue is related to the fact that calling a member function is allowed on an rvalue, an anomaly that D inherited from C++. Andrei
Jan 11 2009