digitalmars.D - Properties
- Vishaal (3/3) Jan 07 2009 Properties, such as array.length, should return lvalues to allow:
- BCS (3/6) Jan 07 2009 I think there is a (long standing) bug report about that one. Maybe if e...
- Moritz Warning (3/12) Jan 07 2009 http://d.puremagic.com/issues/show_bug.cgi?id=808
- dsimcha (18/24) Jan 07 2009 Yeah, this has been mentioned in the past before. The most obvious way ...
- Vishaal (4/31) Jan 07 2009 The two methods aren't mutually exclusive. We could let users write opAd...
- Michiel Helvensteijn (28/46) Jan 08 2009 I've always thought properties should work somewhat like this:
- Nick Sabalausky (30/78) Jan 08 2009 Agreed. The current way is just sloppy and it bothers me constantly. *gr...
- Michiel Helvensteijn (16/46) Jan 08 2009 I have to disagree. By that logic, we would abolish parameter-names
- Ary Borenszweig (10/31) Jan 08 2009 It's very different. A setter has a very specific meaning: set some
- Michiel Helvensteijn (5/17) Jan 08 2009 It's not for me to say. It should be up to the programmer.
- Ary Borenszweig (5/21) Jan 08 2009 Yes, three. And that's it. That was my point. And they all have pretty
- Michiel Helvensteijn (6/20) Jan 08 2009 Perhaps the implicit declaration "value" (or whatever *you* would call i...
- Nick Sabalausky (8/27) Jan 08 2009 Overshadowing is already a potential issue anyway, with or without
- Michiel Helvensteijn (9/21) Jan 08 2009 Sure, but in that case both of the declarations are explicit. Now there'...
- Nick Sabalausky (12/33) Jan 08 2009 Possibly. But I've used it a lot in C# and never had a problem. And synt...
- Chad J (44/73) Jan 08 2009 That's not quite why it was suggested.
- bearophile (12/23) Jan 08 2009 I think I have suggested something similar, time ago.
- Nick Sabalausky (14/40) Jan 08 2009 Something like this:
- Yigal Chripun (27/73) Jan 08 2009 I like the general idea, but why invent new words?
- Nick Sabalausky (12/93) Jan 08 2009 *smacks forehead* I completely forget about "outer". That's the only rea...
- Nick Sabalausky (23/96) Jan 08 2009 That I don't like, for the same reason VB's syntax for returning a value...
- Chad J (2/3) Jan 08 2009 I agree, good call.
- Miles (16/40) Jan 08 2009 That defeats one of the purposes of properties. A property is usually an
- Nick Sabalausky (98/138) Jan 08 2009 This proposal doesn't prevent any of that. Suppose our syntax was like i...
- Miles (16/45) Jan 09 2009 The problem I see with this is that it complicates the implementation of
- Nick Sabalausky (40/86) Jan 08 2009 I don't think that follows at all. Function parameters have user-definab...
- Nick Sabalausky (3/35) Jan 08 2009 Sorry, Ary beat me to it. And much less verbosely ;)
- Miles (16/19) Jan 08 2009 Both the getter and the setter should return an rvalue. Properties exist
- Bill Baxter (39/48) Jan 08 2009 Partly, but also properties exist to provide encapsulation of private st...
- Nick Sabalausky (4/13) Jan 08 2009 He said "rvalue", not "lvalue". I actually made that same mistake the fi...
- Bill Baxter (4/18) Jan 08 2009 Wow. You're right. Maybe I need to change my font or something.
- Miles (29/35) Jan 08 2009 Wait! Read again what I said... getters and setters should return an
- Bill Baxter (4/39) Jan 08 2009 Ok! I'm in agreement with you totally on all that. Sorry for the
- Nick Sabalausky (30/49) Jan 08 2009 True, but my main point was, however the language ends up handling the
- Miles (35/57) Jan 08 2009 In this case, simplifying would be more complex.
- Nick Sabalausky (7/67) Jan 08 2009 Ok, you've convinced me on this.
- Miles (9/13) Jan 09 2009 Ok. But I think such feature would create a mess. For example:
- Nick Sabalausky (3/18) Jan 09 2009 Like I said, I'm neither advocating nor condemning overload-on-return-va...
- Chad J (11/17) Jan 08 2009 I agree, though let's not fool ourselves, there is at least one corner c...
- Yigal Chripun (27/43) Jan 09 2009 that's solvable. as I noted in a previous post, a property seems to me
- Michel Fortin (18/30) Jan 09 2009 Hum, that doesn't really work. Getter and setters of the property have
- Yigal Chripun (6/32) Jan 09 2009 instead of manually doing it within the struct just do s/struct/class to...
- Miles (10/22) Jan 09 2009 Yes, this is a corner case. If the getter is not set to return an
- Daniel Keep (23/24) Jan 09 2009 I might be old fashioned (get offa mah lawn!), but I've always found
- dsimcha (15/18) Jan 09 2009 This is precisely the attitude that left C++ with all of the cruft and b...
- Andrei Alexandrescu (23/43) Jan 09 2009 Well I'm not so sure about that. In fact I'd go as far as saying you're
- dsimcha (23/54) Jan 09 2009 I will admit that cruft and baggage were probably poor word choices to d...
- Nick Sabalausky (10/34) Jan 09 2009 String mixins are very powerful, and certainly welcome IMO, but they inv...
- Daniel Keep (28/36) Jan 09 2009 I think the comparison is a bit loose; the problem with ASP and PHP was
- Nick Sabalausky (52/74) Jan 09 2009 It's not so much an issue of logic vs display (if you're using a somewha...
- bearophile (6/10) Jan 09 2009 I agree. String mixin are generally near-unreadable, and I hate to debug...
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (22/40) Jan 10 2009 -----BEGIN PGP SIGNED MESSAGE-----
- Daniel Keep (29/62) Jan 10 2009 For me, it *was* a case of access-control... at least, it was about 80%
- Nick Sabalausky (3/65) Jan 10 2009 Same reason we have "while" and "foreach" in addition to "for".
- Daniel Keep (23/33) Jan 10 2009 How is this:
- Miles (30/31) Jan 10 2009 One good distinction properties and normal functions ought to make is
- dsimcha (12/41) Jan 10 2009 Why? This is really superfluous. I for one think that code is often mo...
- Miles (22/35) Jan 10 2009 It introduces ambiguities, and unexpected behavior, as I exemplified in
- Bill Baxter (11/30) Jan 10 2009 Not sure what you mean by that. It's just foo vs &foo in most cases.
- Nick Sabalausky (17/48) Jan 10 2009 I'd consider those situations with delegates to be reason enough.
- Frits van Bommel (8/17) Jan 12 2009 That just can't work without radically changing what a pointer is.
- Nick Sabalausky (6/23) Jan 12 2009 What if properties were internally defined to be a struct of two delegat...
- Miles (74/84) Jan 11 2009 It is more tied with the intuitive use of symbols. 'foo' is a function,
- bearophile (5/13) Jan 11 2009 Seeing how much experimental D2 is, I think there's time to fix design b...
- Nick Sabalausky (6/18) Jan 11 2009 Even if it weren't for that, I would still consider this important enoug...
- bearophile (8/12) Jan 11 2009 But I am not sure that proposed idea is the best, because in Python (tha...
- Nick Sabalausky (8/23) Jan 11 2009 Yes, but 1. As you indicated, it could only happen in D when using an
- bearophile (5/10) Jan 11 2009 That's what I was saying, to disallow "foo" without () or &. It's not th...
- Denis Koroskin (8/21) Jan 11 2009 Yes, this is the best design so far.
- Sergey Kovrov (10/15) Jan 11 2009 As far as I understand calling built-in properties eg.
- Denis Koroskin (3/19) Jan 11 2009 Absolutely agree here.
- Christopher Wright (6/19) Jan 12 2009 So you consider functions to be a reference type, since the value of a
- Miles (2/5) Jan 13 2009 Yes, almost equivalent.
- Bill Baxter (22/46) Jan 10 2009 I think the point is not that someone would do these things
- Andrei Alexandrescu (6/40) Jan 10 2009 Walter and I see eye to eye that a possible solution would be to only
- Nick Sabalausky (6/26) Jan 10 2009 I think that's a big part of the problem though. The current strategy ju...
- Denis Koroskin (89/123) Jan 10 2009 It was criticized many times by different people as being a too complex ...
- Miles (6/9) Jan 11 2009 That would only patch a single consequence of the much bigger core
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (15/37) Jan 11 2009 -----BEGIN PGP SIGNED MESSAGE-----
- Bill Baxter (9/35) Jan 11 2009 a
- Nick Sabalausky (88/90) Jan 10 2009 I'd say the point of properties is both a matter of clean implementation...
- Michiel Helvensteijn (4/5) Jan 11 2009 Hear, hear!
- Nick Sabalausky (7/9) Jan 11 2009 That should probably be:
- John Reimer (4/7) Jan 11 2009 Umm... May I make a little correction here?
- Nick Sabalausky (15/22) Jan 11 2009 Maybe there's examples I'm not thinking of, and I'm certainly no natural...
- Jarrett Billingsley (10/23) Jan 11 2009 That "red" can be used as both a noun and as an adjective is just a
- John Reimer (14/43) Jan 11 2009 No problem. I am not saying a word can't be /used/ as an adjective and ...
- Nick Sabalausky (8/51) Jan 12 2009 I guess that's a difference between natural languages and oop-languages
- John Reimer (16/68) Jan 12 2009 Yes, although natural languages and programming languages might share so...
- Benji Smith (10/40) Jan 12 2009 Incidentally...
- John Reimer (6/52) Jan 12 2009 Interesting. There is certainly room to play here. I never thought of ...
- Christopher Wright (5/48) Jan 13 2009 It's a genitive phrase, not an adjective. You couldn't say "That
- John Reimer (10/65) Jan 13 2009 The reason I conceeded a little on this one is because of http://en.wiki...
- Christopher Wright (4/15) Jan 12 2009 No programming language that I know distinguishes parts of an object
- John Reimer (6/22) Jan 12 2009 Yes, I was not critiquing his commentary on programming languages: it wo...
- dsimcha (16/16) Jan 10 2009 I'm starting to think that this properties thing is becoming a hopelessl...
- Bill Baxter (10/26) Jan 10 2009 Well, foo+=1 is not the only issue. It may have been the one that
- Chad J (33/51) Jan 10 2009 foo = foo + 1 vs foo += 1 is not the only issue here. Indeed, it is
- Miles (19/27) Jan 11 2009 Sure. It is bad coding style, it is ugly and the programmer who does
- Benji Smith (16/51) Jan 12 2009 Or the compiler could prevent properties from returning mutable structs?
- Don (7/34) Jan 08 2009 It was recently pointed out in another thread that if prop is a class,
- Ellery Newcomer (2/12) Jan 07 2009 Gripe gripe gripe gripe gripe
- =?UTF-8?B?QWxleGFuZGVyIFDDoW5law==?= (2/15) Jan 07 2009 Guriiiiipe. Gripe gripe. GRIPE.
- bearophile (4/5) Jan 08 2009 Is this the second (redundant) system to vote for the most hated bugs?
- Daniel Keep (6/13) Jan 08 2009 Maybe we need a bot to monitor bugs' GPS [1]. You can never have too
-
Mike James
(3/3)
Jan 08 2009
- Denis Koroskin (44/47) Jan 10 2009 I'd like to point out another related issue that everyone seems to miss.
-
Christopher Wright
(14/21)
Jan 11 2009
- Andrei Alexandrescu (5/78) Jan 11 2009 This is a very strong argument. The issue is related to the fact that
Properties, such as array.length, should return lvalues to allow: a.length += 8; or other similar statements.
Jan 07 2009
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
On Thu, 08 Jan 2009 00:49:38 +0000, BCS wrote:Reply to Vishaal,http://d.puremagic.com/issues/show_bug.cgi?id=808 *gripes*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
== Quote from BCS (ao pathlink.com)'s articleReply to Vishaal,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.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
dsimcha Wrote:== Quote from BCS (ao pathlink.com)'s articleThe 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;Reply to Vishaal,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.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
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
"Michiel Helvensteijn" <nomail please.com> wrote in message news:gk4oi2$14tv$1 digitalmars.com...dsimcha wrote: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.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++; } }
Jan 08 2009
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 thatI 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
Michiel Helvensteijn wrote:Nick Sabalausky 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? 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."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 thatI 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 bebetter 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
Ary Borenszweig wrote: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. -- MichielIt'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?get { return this.len; } like thatI 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.
Jan 08 2009
Michiel Helvensteijn wrote:Ary Borenszweig wrote: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. :-PIt's not for me to say. It should be up to the programmer. You've already shown that there are at least three possibilities.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?get { return this.len; } like thatI 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.
Jan 08 2009
Ary Borenszweig 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. -- MichielYes, 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. :-PIt'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.
Jan 08 2009
"Michiel Helvensteijn" <nomail please.com> wrote in message news:gk5f80$2lav$1 digitalmars.com...Ary Borenszweig wrote: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).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.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. :-PIt'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.
Jan 08 2009
Nick Sabalausky wrote: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.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).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
"Michiel Helvensteijn" <nomail please.com> wrote in message news:gk5h9r$2p7g$1 digitalmars.com...Nick Sabalausky wrote:like a keyword than my purely tentative "newValue").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.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.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.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?
Jan 08 2009
Michiel Helvensteijn wrote:Nick Sabalausky wrote: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.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.
Jan 08 2009
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
"bearophile" <bearophileHUGS lycos.com> wrote in message news:gk5grh$2o8i$1 digitalmars.com...Chad J:Something like this: public property int var { get { return property; } set { property = $; } } Or something like this: public property int foo { get { return $; } set { $ = $new; } }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
Nick Sabalausky wrote:"bearophile"<bearophileHUGS lycos.com> wrote in message news:gk5grh$2o8i$1 digitalmars.com...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; ... }Chad J:Something like this: public property int var { get { return property; } set { property = $; } } Or something like this: public property int foo { get { return $; } set { $ = $new; } }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
"Yigal Chripun" <yigal100 gmail.com> wrote in message news:gk5t92$fu2$1 digitalmars.com...Nick Sabalausky wrote:*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; }"bearophile"<bearophileHUGS lycos.com> wrote in message news:gk5grh$2o8i$1 digitalmars.com...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.Chad J:Something like this: public property int var { get { return property; } set { property = $; } } Or something like this: public property int foo { get { return $; } set { $ = $new; } }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, bearophileit 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
"Chad J" <gamerchad __spam.is.bad__gmail.com> wrote in message news:gk5fch$2ldo$1 digitalmars.com...Michiel Helvensteijn wrote: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.Nick Sabalausky wrote: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.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.
Jan 08 2009
Nick Sabalausky wrote:It's a DRY violation.I agree, good call.
Jan 08 2009
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
"Miles" <_______ _______.____> wrote in message news:gk68q1$19g1$1 digitalmars.com...Chad J 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($); } } --------------- 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 } ---------------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.See above.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
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
"Michiel Helvensteijn" <nomail please.com> wrote in message news:gk5b4m$2ekd$1 digitalmars.com...Nick Sabalausky wrote: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."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 thatI 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.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...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).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.
Jan 08 2009
"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...Sorry, Ary beat me to it. And much less verbosely ;)Nick Sabalausky wrote: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.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 thatI have to disagree. By that logic, we would abolish parameter-names altogether and access formal parameters by number.
Jan 08 2009
Nick Sabalausky wrote:A property setter is ALWAYS going to return nothing andBoth 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
On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:Nick Sabalausky wrote: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.A property setter is ALWAYS going to return nothing andBoth 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 buttonI 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
"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:He said "rvalue", not "lvalue". I actually made that same mistake the first couple times I read it.Nick Sabalausky wrote: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.A property setter is ALWAYS going to return nothing andBoth the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
Jan 08 2009
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...Wow. You're right. Maybe I need to change my font or something. Sorry for the rant about returning lvalues then! --bbOn Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote:He said "rvalue", not "lvalue". I actually made that same mistake the first couple times I read it.Nick Sabalausky wrote: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.A property setter is ALWAYS going to return nothing andBoth the getter and the setter should return an rvalue. Properties exist so that they are interchangeable with real member variables.
Jan 08 2009
Bill Baxter wrote:On Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote: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.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.
Jan 08 2009
On Fri, Jan 9, 2009 at 11:01 AM, Miles <_______ _______.____> wrote:Bill Baxter wrote:Ok! I'm in agreement with you totally on all that. Sorry for the lvalue/rvalue mixup. --bbOn Fri, Jan 9, 2009 at 9:59 AM, Miles <_______ _______.____> wrote: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.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.
Jan 08 2009
"Miles" <_______ _______.____> wrote in message news:gk67hr$17d9$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. 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.A property setter is ALWAYS going to return nothing andBoth 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.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 }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
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
"Miles" <_______ _______.____> wrote in message news:gk6f9p$1jve$1 digitalmars.com...Nick Sabalausky wrote:Ok, you've convinced me on this.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.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.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
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
"Miles" <_______ _______.____> wrote in message news:gk7fau$f38$1 digitalmars.com...Nick Sabalausky wrote:Like I said, I'm neither advocating nor condemning overload-on-return-value.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
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
Chad J wrote:Miles wrote: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".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 09 2009
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
Michel Fortin wrote:On 2009-01-09 05:47:26 -0500, Yigal Chripun <yigal100 gmail.com> said: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.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; }
Jan 09 2009
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
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
== Quote from Daniel Keep (daniel.keep.lists gmail.com)'s articleWhy 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
dsimcha wrote:== Quote from Daniel Keep (daniel.keep.lists gmail.com)'s articleWell 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.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.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
== 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.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?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?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.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
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:gk7nij$rlo$1 digitalmars.com...Michiel Helvensteijn 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.[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
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
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:gk8j4h$29fm$1 digitalmars.com...Nick Sabalausky wrote: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.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?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
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
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Daniel Keep wrote:Michiel Helvensteijn wrote: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-----[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; ")); }
Jan 10 2009
Jérôme M. Berger wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Daniel Keep wrote: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.Michiel Helvensteijn wrote: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).[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; ")); }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? :PHow would you do that with mixins? (Not that it would be impossible, but the syntax would probably be horrible). JeromeOn 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
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:gk9v33$1bvu$1 digitalmars.com...Jérôme M. Berger wrote:Same reason we have "while" and "foreach" in addition to "for".-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Daniel Keep wrote: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.Michiel Helvensteijn wrote: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).[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; ")); }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? :PHow would you do that with mixins? (Not that it would be impossible, but the syntax would probably be horrible). JeromeOn 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
Nick Sabalausky wrote:"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:gk9v33$1bvu$1 digitalmars.com...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[snip] What would be the point of making a special syntax when you can already do that? :PSame reason we have "while" and "foreach" in addition to "for".
Jan 10 2009
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
== Quote from Miles (_______ _______.____)'s articleDaniel Keep wrote: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().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 ----------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
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
On Sun, Jan 11, 2009 at 12:01 PM, Miles <_______ _______.____> wrote:dsimcha 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. I agree that 'except for' is not very pleasant.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.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. --bbThis 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.
Jan 10 2009
"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:I'd consider those situations with delegates to be reason enough.dsimcha 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.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.I agree that 'except for' is not very pleasant.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.)He may want to retain the ability to pass it as a delegate to some other function too.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.
Jan 10 2009
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
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message news:gkfmr2$1n9j$1 digitalmars.com...Nick Sabalausky wrote: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...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.
Jan 12 2009
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
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
"bearophile" <bearophileHUGS lycos.com> wrote in message news:gkd3b0$fkb$1 digitalmars.com...Miles: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.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.
Jan 11 2009
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
"bearophile" <bearophileHUGS lycos.com> wrote in message news:gkd53n$ikt$1 digitalmars.com...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. 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?)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.
Jan 11 2009
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
On Sun, 11 Jan 2009 21:52:27 +0300, bearophile <bearophileHUGS lycos.com> wrote:Nick Sabalausky: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.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
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; // etcAs 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
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:'&' 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'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; // etcAs 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.Absolutely agree here.
Jan 11 2009
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
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
On Sun, Jan 11, 2009 at 11:27 AM, dsimcha <dsimcha yahoo.com> wrote:== Quote from Miles (_______ _______.____)'s articleI 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. --bbDaniel Keep wrote: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().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 ----------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.
Jan 10 2009
Miles wrote:Daniel Keep 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.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.Well the above syntaxes could be forbidden other ways too. Andrei
Jan 10 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gkbtpo$1jq0$1 digitalmars.com...Miles wrote: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.Daniel Keep 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.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 ----------
Jan 10 2009
On Sun, 11 Jan 2009 07:50:03 +0300, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Miles wrote: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:Daniel Keep 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.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 ----------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.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
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
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Andrei Alexandrescu wrote:Miles wrote: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-----Daniel Keep 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.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 ----------
Jan 11 2009
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:aMiles wrote:Daniel Keep wrote: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=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 ----------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. --bbfunction a(). All of the above can be fixed within that framework.Won't work: how do you then create a write-only property?
Jan 11 2009
"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
Nick Sabalausky wrote:<Great Example>Hear, hear! -- Michiel
Jan 11 2009
"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
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
"John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...Hello Nick,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.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
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
Hello Nick,"John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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. -JJRHello Nick,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.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
"John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119bd8cb4246de86cc80 news.digitalmars.com...Hello Nick,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."John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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.Hello Nick,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.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. -JJRIt 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
Hello Nick,"John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119bd8cb4246de86cc80 news.digitalmars.com...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. -JJRHello Nick,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."John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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.Hello Nick,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.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 12 2009
Nick Sabalausky wrote:"John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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. --benjiHello Nick,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.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 12 2009
Hello Benji,Nick Sabalausky wrote: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"John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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. --benjiHello Nick,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.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 12 2009
Benji Smith wrote:Nick Sabalausky wrote: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.""John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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".Hello Nick,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.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. -JJRFor 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
Hello Christopher,Benji Smith wrote: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... -JJRNick Sabalausky wrote: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.""John Reimer" <terminal.node gmail.com> wrote in message news:28b70f8c119528cb42154f5d14e0 news.digitalmars.com...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".Hello Nick,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.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. -JJRFor 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
John Reimer wrote:Hello Nick,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.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 12 2009
Hello Christopher,John Reimer wrote: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. -JJRHello Nick,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.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 12 2009
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
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
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
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
Miles wrote:dsimcha wrote: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. --benjiI 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 12 2009
dsimcha wrote:== Quote from BCS (ao pathlink.com)'s articleIt 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'sReply to Vishaal,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,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!)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
BCS wrote:Reply to Vishaal,Gripe gripe gripe gripe gripeProperties, 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
Ellery Newcomer wrote:BCS wrote:Guriiiiipe. Gripe gripe. GRIPE.Reply to Vishaal,Gripe gripe gripe gripe gripeProperties, 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
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
bearophile wrote:Alexander Pánek: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.Guriiiiipe. Gripe gripe. GRIPE.Is this the second (redundant) system to vote for the most hated bugs? Bye, bearophile
Jan 08 2009
<fx chanting vikings in background> Gripe, Gripe, Gripe. Gripe, Gripe, Gripe, Wonderful Gripe... </fx>
Jan 08 2009
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
Denis Koroskin wrote:On Thu, 08 Jan 2009 03:45:08 +0300, Vishaal <vishaal nospam.com> wrote:<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 warningsProperties, 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.
Jan 11 2009
Denis Koroskin wrote:On Thu, 08 Jan 2009 03:45:08 +0300, Vishaal <vishaal nospam.com> wrote: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++. AndreiProperties, 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 11 2009