digitalmars.D - Properties: a.b.c = 3
- Walter Bright (7/7) Jul 28 2009 The issue is what if b is a property, returns a temporary object, and
- Ary Borenszweig (4/14) Jul 28 2009 Maybe only if the return value of the property is a struct? For class
- Lionello Lunesu (5/19) Jul 29 2009 What if structure B has get/set c and B.c(int) does something non-local?...
- KennyTM~ (2/26) Jul 29 2009 No, you should tell the author of struct B to revise the design :p
- BLS (6/16) Jul 28 2009 What I don't see is why a property isn't just a property. What you
- Walter Bright (2/5) Jul 28 2009 Even returning an 'int' is a temporary object.
- BLS (2/8) Jul 28 2009 ?
- Nick Sabalausky (3/11) Jul 28 2009 He means it's a temporary value, not actually an object.
- BLS (3/21) Jul 28 2009 So int'max is a property int'ILikeIt() definitely not.
- Andrei Alexandrescu (3/26) Jul 28 2009 I don't understand, could you please elaborate?
- BLS (8/36) Jul 28 2009 Sure,
- Franklin Minty (2/43) Jul 29 2009 Unless it's the famous Mr Ed...
- davidl (5/12) Jul 28 2009 A property should never return temp obj in the first place.
- Walter Bright (2/3) Jul 28 2009 That's unworkable - it means you cannot have user defined types.
- Daniel Keep (7/17) Jul 28 2009 Maybe the compiler could rewrite the above as:
- Nick Sabalausky (4/21) Jul 28 2009 That's how I've always felt about it. I don't think any other approach
- Chad J (16/37) Jul 28 2009 YES.
- Nick Sabalausky (50/60) Jul 30 2009 Same here, so I just did a little test in Visual C# 2008 Express. Turns ...
- Steven Schveighoffer (4/31) Jul 30 2009 Change Rect to a struct, try again. Classes are reference types (note, ...
- Ary Borenszweig (3/39) Jul 30 2009 It gives a compiler error, I already posted that somewhere else:
- Nick Sabalausky (4/37) Jul 30 2009 Oops, yea, you're right. With Rect as a struct it fails to compile
- Andrei Alexandrescu (4/76) Jul 30 2009 As far as I understand, this example is not relevant because there are
- Zhenyu Zhou (5/13) Jul 29 2009 I think b should be const if it is a temporary object.
- grauzone (14/22) Jul 29 2009 Yes! At least that's what the user wants.
- Steven Schveighoffer (12/32) Jul 29 2009 Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one
- Andrei Alexandrescu (7/49) Jul 29 2009 Agreed. But it would be nice if they didn't allowed code with identical
- Bill Baxter (5/7) Jul 29 2009 It's a problem, but not a problem of properties. Just a problem of
- Andrei Alexandrescu (4/11) Jul 29 2009 Yes. It is particularly exacerbated by properties because of the
- KennyTM~ (14/28) Jul 29 2009 and opDot().
- Steven Schveighoffer (29/37) Jul 29 2009 Here is a struct, defined in a .di file:
- Andrei Alexandrescu (3/40) Jul 29 2009 By making a conservative decision.
- Ary Borenszweig (2/44) Jul 29 2009 Yay! :-)
- Steven Schveighoffer (5/38) Jul 30 2009 If we have restrictive shit like this where the compiler thinks it knows...
- Andrei Alexandrescu (5/45) Jul 30 2009 It's a matter of degree. There's already plenty of correct code that D
- grauzone (9/41) Jul 29 2009 I don't want to type out that mess as a user either...
- Steven Schveighoffer (12/50) Jul 29 2009 What I meant was, I wouldn't want something like a.b.c.d.e.f = 3 to
- Chad J (12/70) Jul 29 2009 So we could have semantics that actually work, but you don't want them
- Chad J (5/78) Jul 29 2009 Thinking about it a little more, the extra temporaries could run you out
- grauzone (2/4) Jul 29 2009 Temporaries can be on the stack. That's not a problem.
- Bill Baxter (3/8) Jul 29 2009 How is that not a performance issue? The stack is in main memory.
- Chad J (7/17) Jul 29 2009 This is where my knowledge starts to run a bit thin.
- Chad J (6/25) Jul 29 2009 Also, really deep dot chains are unlikely to happen. I just feel like
- Benji Smith (9/34) Jul 30 2009 Especially especially because, if you prevent the a.b.c = x syntax, the
- Steven Schveighoffer (20/82) Jul 29 2009 Hold on a second, don't we already have semantics that work? I mean we ...
- Chad J (13/48) Jul 29 2009 Ah, well that argument has some weight.
- Zhenyu Zhou (8/35) Jul 29 2009 What about:
- Chad J (15/24) Jul 29 2009 You'll fall into the trap unless you know about immutable. Said another
- Zhenyu Zhou (15/36) Jul 29 2009 Maybe this is what you want
- Chad J (15/55) Jul 30 2009 The point is to make sure that when a property's member appears on the
- Nick Sabalausky (7/18) Jul 30 2009 I've dealt with that sort of thing in C# and it's a trivial issue. When ...
- Steven Schveighoffer (4/26) Jul 30 2009 Rect has 4 values (x, y, width, height), otherwise, the example doesn't ...
- Nick Sabalausky (7/34) Jul 30 2009 I've dealt with that as well, and done both of these (though not at the ...
- Benji Smith (33/56) Jul 30 2009 It's kind of a moot point anyhow, because most respectable graphics
- Steven Schveighoffer (59/104) Jul 30 2009 Simply that the compiler assumes it's simply setting a value. However, ...
- Chad J (61/147) Jul 31 2009 That's a problem of library design and code architecture, nothing
- grauzone (15/71) Jul 29 2009 The thing above was just the consequence of Daniel Keep's idea of
- Chad J (14/23) Jul 29 2009 Just say no. It is far easier to optimize the nesting assignments. It
- Chad J (30/74) Jul 29 2009 But you don't /have/ to type out that mess! Why would anyone do that?!
- Steven Schveighoffer (14/88) Jul 29 2009 Wouldn't the compiler write:
- Chad J (8/111) Jul 29 2009 It would.
- Chad J (30/56) Jul 29 2009 I should probably explain this more.
- Benji Smith (5/60) Jul 30 2009 And, in fact, this exact kind of optimization is made very simple if the...
- Chad J (13/59) Jul 29 2009 !!!
- Sergey Gromov (12/32) Jul 29 2009 vote++
- Jarrett Billingsley (9/11) Jul 28 2009 So, the issue is that 'a.b()' returns a struct by value. Such return
- Daniel Keep (9/22) Jul 28 2009 Problem: what if .b is computed? Take .length as an example; the setter
- Jarrett Billingsley (19/38) Jul 29 2009 hat
- Benji Smith (8/22) Jul 30 2009 I think the compiler should only rewrite the code (as above) if a.b()
- Chad J (13/40) Jul 31 2009 I believe it is.
- Kagamin (10/14) Jul 29 2009 Does this problem pertain to properties?
- Andrei Alexandrescu (12/30) Jul 29 2009 The code above is only loosely related. The code above contains a
- Kagamin (5/18) Jul 29 2009 That's idealistic view of things. A programmer's imagination used to be ...
- Andrei Alexandrescu (4/11) Jul 29 2009 IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete
- Kagamin (2/13) Jul 29 2009 Never saw this problem in C#. They have problems with understanding and ...
- Andrei Alexandrescu (4/19) Jul 29 2009 Of course you didn't. This is because C# doesn't have it - their structs...
- Denis Koroskin (3/21) Jul 29 2009 I believe you can still return a struct from an object via property.
- Ary Borenszweig (20/41) Jul 29 2009 Yes they can. And also C# shows us the solution to the problem (similar
- Jarrett Billingsley (5/52) Jul 29 2009 o
- Bill Baxter (12/67) Jul 29 2009 rote:
- KennyTM~ (7/66) Jul 29 2009 Probably Walter means
- Bill Baxter (7/90) Jul 29 2009 it
- Steven Schveighoffer (3/6) Jul 29 2009 Impossible with the current implementation -- &a.b is a delegate :)
- Bill Baxter (8/14) Jul 29 2009 :
- Bill Baxter (5/20) Jul 29 2009 [edit]
- Bill Baxter (11/94) Jul 29 2009 it
- Andrei Alexandrescu (7/14) Jul 29 2009 Well the problem is that a.b().c = 5 makes it clear that there's a
- Ary Borenszweig (5/17) Jul 29 2009 No. Whenever you do
- Andrei Alexandrescu (3/23) Jul 29 2009 I don't think D allows expressions to the right of ".".
- Ary Borenszweig (4/27) Jul 29 2009 Ok, then change the rule to
- Andrei Alexandrescu (5/35) Jul 29 2009 How about this fella then.
- Ary Borenszweig (7/47) Jul 29 2009 Not if b[5] is a struct. Do I need to list evey possible syntax there it...
- Steven Schveighoffer (18/21) Jul 29 2009 struct S
- Ary Borenszweig (5/32) Jul 29 2009 Because in the general case it might not work.
- Steven Schveighoffer (7/35) Jul 29 2009 I prefer to have the power to create whatever I want without the compile...
- Ary Borenszweig (8/49) Jul 29 2009 I reply using the web page because Thunderbird gives me a Bad Request er...
- Steven Schveighoffer (17/75) Jul 29 2009 I retracted my original message (just found out how to do that), because...
- Andrei Alexandrescu (12/39) Jul 29 2009 Simpler yet:
- Andrei Alexandrescu (3/47) Jul 29 2009 Yes, you actually need to. It was the point of my post.
- Rainer Deyke (6/11) Jul 29 2009 Simple rule: rvalues cannot be modified (i.e. rvalues are implicitly
- Bill Baxter (13/27) Jul 29 2009 tion
- Andrei Alexandrescu (18/46) Jul 29 2009 Not quite. If they were completelty indistinguishable from fields,
- Ary Borenszweig (12/67) Jul 29 2009 I don't know why you keep discussing this if C# already implements it
- Chad J (4/51) Jul 29 2009 What about something like "array.length++;"?
- Nick Sabalausky (9/28) Jul 30 2009 C# shows us *A* solution. Doesn't mean we can't do one better.
- Ary Borenszweig (24/61) Jul 30 2009 I don't understand your example. What's wrong with it? What doesn't work...
- Nick Sabalausky (27/45) Jul 30 2009 Here's the problem (still in C#):
- Michel Fortin (25/35) Jul 30 2009 I'm undecided about what to do here.
- KennyTM~ (2/12) Jul 29 2009 .... unless it returns a ref.
- Michel Fortin (25/33) Jul 29 2009 With the local namespace approach I propsed a little while ago, you
- Andrei Alexandrescu (5/24) Jul 29 2009 We're looking for a modular solution - one that allows one person to
- Steven Schveighoffer (34/41) Jul 29 2009 There's one way you could do it -- since the return value is a temporary...
- BCS (3/15) Jul 29 2009 seems related to this:
- Jimbob (25/32) Jul 30 2009 Disallow it by default. IE.
- Kagamin (6/18) Jul 31 2009 This is a matter of coding style I believe.
The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.
Jul 28 2009
Walter Bright escribió:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe only if the return value of the property is a struct? For class references it'll work well (except your property returns a new object each time, which is kind of a weird way to implement a property).
Jul 28 2009
"Ary Borenszweig" <ary esperanto.org.ar> wrote in message news:h4ocm1$28k$1 digitalmars.com...Walter Bright escribió:What if structure B has get/set c and B.c(int) does something non-local? Then the function call ("property assignment") should be allowed. L.The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe only if the return value of the property is a struct? For class references it'll work well (except your property returns a new object each time, which is kind of a weird way to implement a property).
Jul 29 2009
Lionello Lunesu wrote:"Ary Borenszweig" <ary esperanto.org.ar> wrote in message news:h4ocm1$28k$1 digitalmars.com...No, you should tell the author of struct B to revise the design :pWalter Bright escribió:What if structure B has get/set c and B.c(int) does something non-local? Then the function call ("property assignment") should be allowed. L.The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. dealing with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe only if the return value of the property is a struct? For class references it'll work well (except your property returns a new object each time, which is kind of a weird way to implement a property).
Jul 29 2009
Walter Bright wrote:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property period If something is exceeding the meaning of property then fire up your keyboard.
Jul 28 2009
BLS wrote:What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property periodEven returning an 'int' is a temporary object.
Jul 28 2009
Walter Bright wrote:BLS wrote:?What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property periodEven returning an 'int' is a temporary object.
Jul 28 2009
"BLS" <windevguy hotmail.de> wrote in message news:h4oeb0$5sr$2 digitalmars.com...Walter Bright wrote:He means it's a temporary value, not actually an object.BLS wrote:?What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property periodEven returning an 'int' is a temporary object.
Jul 28 2009
BLS wrote:Walter Bright wrote:So int'max is a property int'ILikeIt() definitely not. let's keep it simpleThe issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. dealing with this. One thought I had was to simply disallow the '.' to appear after a function style property.What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property period If something is exceeding the meaning of property then fire up your keyboard.
Jul 28 2009
BLS wrote:BLS wrote:I don't understand, could you please elaborate? AndreiWalter Bright wrote:So int'max is a property int'ILikeIt() definitely not. let's keep it simpleThe issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. dealing with this. One thought I had was to simply disallow the '.' to appear after a function style property.What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property period If something is exceeding the meaning of property then fire up your keyboard.
Jul 28 2009
Andrei Alexandrescu wrote:BLS wrote:Sure, int'max will give you (let's assume for a while that the compiler writer was not completely drunken) a useful answer int`ILikeIt() is probabely "green" I guess what I want to say is that a property will give you certainly useful answers depending on it's very own nature... a temporary object not. or : a horse is a horse is a horse of courseBLS wrote:I don't understand, could you please elaborate? AndreiWalter Bright wrote:So int'max is a property int'ILikeIt() definitely not. let's keep it simpleThe issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. dealing with this. One thought I had was to simply disallow the '.' to appear after a function style property.What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property period If something is exceeding the meaning of property then fire up your keyboard.
Jul 28 2009
BLS Wrote:Andrei Alexandrescu wrote:Unless it's the famous Mr Ed...BLS wrote:Sure, int'max will give you (let's assume for a while that the compiler writer was not completely drunken) a useful answer int`ILikeIt() is probabely "green" I guess what I want to say is that a property will give you certainly useful answers depending on it's very own nature... a temporary object not. or : a horse is a horse is a horse of courseBLS wrote:I don't understand, could you please elaborate? AndreiWalter Bright wrote:So int'max is a property int'ILikeIt() definitely not. let's keep it simpleThe issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. dealing with this. One thought I had was to simply disallow the '.' to appear after a function style property.What I don't see is why a property isn't just a property. What you announce is more a kind of "universal maybe these value holder" - a temporary object is not a property period If something is exceeding the meaning of property then fire up your keyboard.
Jul 29 2009
ÔÚ Wed, 29 Jul 2009 10:33:53 +0800£¬Walter Bright <newshound1 digitalmars.com> дµÀ:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.A property should never return temp obj in the first place. -- ʹÓà Opera ¸ïÃüÐԵĵç×ÓÓʼþ¿Í»§³ÌÐò: http://www.opera.com/mail/
Jul 28 2009
davidl wrote:A property should never return temp obj in the first place.That's unworkable - it means you cannot have user defined types.
Jul 28 2009
Walter Bright wrote:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.
Jul 28 2009
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:h4og1p$b3f$1 digitalmars.com...Walter Bright wrote:That's how I've always felt about it. I don't think any other approach really makes any sense.The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.
Jul 28 2009
Daniel Keep wrote:Walter Bright wrote:YES. Anyhow, this is why properties must have their own semantics. Anything else will likely have some nasty corner case that you haven't thought of yet. Just bite the bullet and do this. Put the beast to rest. For another example array.length++; becomes auto t = array.length; t++; array.length = t; Even that case works just like the programmer expects. You'd never have to hear another n00b bitch about "array.length++; doesn't work!!11" ever again.The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.
Jul 28 2009
"Chad J" <chadjoan __spam.is.bad__gmail.com> wrote in message news:h4oku0$uel$1 digitalmars.com...Daniel Keep wrote:Code: -------------------------------------- using System; namespace ConsoleApplication1 { class Program { class Rect { public int width; public int height; public Rect(int width, int height) { this.width = width; this.height = height; } } class Widget { public Rect size { get; set; } public Widget() { size = new Rect(50,50); } } static void Main(string[] args) { Widget wid = new Widget(); Console.Out.WriteLine("width: "+wid.size.width); Console.Out.WriteLine("height: "+wid.size.height); wid.size.width = 100; Console.Out.WriteLine("width: "+wid.size.width); Console.Out.WriteLine("height: "+wid.size.height); Console.ReadLine(); // So I can *read* the dang output } } } -------------------------------------- Compiles successfully. Output: -------------------------------------- width: 50 height: 50 width: 100 height: 50 --------------------------------------Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t;
Jul 30 2009
On Thu, 30 Jul 2009 14:40:21 -0400, Nick Sabalausky <a a.a> wrote:"Chad J" <chadjoan __spam.is.bad__gmail.com> wrote in message news:h4oku0$uel$1 digitalmars.com...Change Rect to a struct, try again. Classes are reference types (note, I -SteveDaniel Keep wrote:out Code: -------------------------------------- using System; namespace ConsoleApplication1 { class Program { class Rect {Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t;memory.
Jul 30 2009
Steven Schveighoffer wrote:On Thu, 30 Jul 2009 14:40:21 -0400, Nick Sabalausky <a a.a> wrote:It gives a compiler error, I already posted that somewhere else: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=94292"Chad J" <chadjoan __spam.is.bad__gmail.com> wrote in message news:h4oku0$uel$1 digitalmars.com...Change Rect to a struct, try again. Classes are reference types (note,Daniel Keep wrote:Turns out Code: -------------------------------------- using System; namespace ConsoleApplication1 { class Program { class Rect {Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t;memory.
Jul 30 2009
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.uxv89qjieav7ka localhost.localdomain...On Thu, 30 Jul 2009 14:40:21 -0400, Nick Sabalausky <a a.a> wrote:Oops, yea, you're right. With Rect as a struct it fails to compile complaining (in it's own words) that size is not an lvalue."Chad J" <chadjoan __spam.is.bad__gmail.com> wrote in message news:h4oku0$uel$1 digitalmars.com...Change Rect to a struct, try again. Classes are reference types (note, IDaniel Keep wrote:out Code: -------------------------------------- using System; namespace ConsoleApplication1 { class Program { class Rect {Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t;memory.
Jul 30 2009
Nick Sabalausky wrote:"Chad J" <chadjoan __spam.is.bad__gmail.com> wrote in message news:h4oku0$uel$1 digitalmars.com...As far as I understand, this example is not relevant because there are no structs involved. AndreiDaniel Keep wrote:Code: -------------------------------------- using System; namespace ConsoleApplication1 { class Program { class Rect { public int width; public int height; public Rect(int width, int height) { this.width = width; this.height = height; } } class Widget { public Rect size { get; set; } public Widget() { size = new Rect(50,50); } } static void Main(string[] args) { Widget wid = new Widget(); Console.Out.WriteLine("width: "+wid.size.width); Console.Out.WriteLine("height: "+wid.size.height); wid.size.width = 100; Console.Out.WriteLine("width: "+wid.size.width); Console.Out.WriteLine("height: "+wid.size.height); Console.ReadLine(); // So I can *read* the dang output } } } -------------------------------------- Compiles successfully. Output: -------------------------------------- width: 50 height: 50 width: 100 height: 50 --------------------------------------Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t;
Jul 30 2009
Daniel Keep Wrote:Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.I think b should be const if it is a temporary object. And the compiler will tell you that a.b.c is read only. Otherwise, don't make it look like a property: a.createNewB().c = 3;
Jul 29 2009
Daniel Keep wrote:Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???
Jul 29 2009
On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want. Properties don't have to be exactly like fields. I think we need to get away from that idea. It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible. I don't believe the problem needs to be solved. -SteveMaybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:Agreed. But it would be nice if they didn't allowed code with identical syntax and useless semantics.Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want. Properties don't have to be exactly like fields. I think we need to get away from that idea.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible.I think it is eminently possible, but we must figure a solution that doesn't complicate the language all too much.I don't believe the problem needs to be solved.To me it looks like an essential problem. Andrei
Jul 29 2009
On Wed, Jul 29, 2009 at 11:08 AM, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:It's a problem, but not a problem of properties. Just a problem of temporary return values in general. --bbI don't believe the problem needs to be solved.To me it looks like an essential problem.
Jul 29 2009
Bill Baxter wrote:On Wed, Jul 29, 2009 at 11:08 AM, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:Yes. It is particularly exacerbated by properties because of the syntactical deception. AndreiIt's a problem, but not a problem of properties. Just a problem of temporary return values in general.I don't believe the problem needs to be solved.To me it looks like an essential problem.
Jul 29 2009
Andrei Alexandrescu wrote:Bill Baxter wrote:and opDot(). struct S { int s; } class X { S opDot() { S temp; temp.s = 6; return temp; } } X z = new X; assert(z.s == 6); z.s = 3; assert(z.s == 6); So, can we stop considering this general problem as a barrier for properties? Or just remove opDot() altogether.On Wed, Jul 29, 2009 at 11:08 AM, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:Yes. It is particularly exacerbated by propertiesIt's a problem, but not a problem of properties. Just a problem of temporary return values in general.I don't believe the problem needs to be solved.To me it looks like an essential problem.because of the syntactical deception. Andrei
Jul 29 2009
On Wed, 29 Jul 2009 14:08:18 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:Here is a struct, defined in a .di file: struct S { private int _c; int c(); void c(int n); } struct S2 { S b(); } Now, in your main file you have: void main() { S2 a; a.b.c = 3; } How in the world is the compiler supposed to know whether to allow this or not? What if the actual code for S looks like this: struct S { private int _c; int c() {return *(cast(int*)_c);} void c(int n) {*(cast(int*)_c) = n;} } Shouldn't this be allowed? -SteveIt would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible.I think it is eminently possible, but we must figure a solution that doesn't complicate the language all too much.
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 14:08:18 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:By making a conservative decision. AndreiSteven Schveighoffer wrote:Here is a struct, defined in a .di file: struct S { private int _c; int c(); void c(int n); } struct S2 { S b(); } Now, in your main file you have: void main() { S2 a; a.b.c = 3; } How in the world is the compiler supposed to know whether to allow this or not?It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible.I think it is eminently possible, but we must figure a solution that doesn't complicate the language all too much.
Jul 29 2009
Andrei Alexandrescu wrote:Steven Schveighoffer wrote:Yay! :-)On Wed, 29 Jul 2009 14:08:18 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:By making a conservative decision. AndreiSteven Schveighoffer wrote:Here is a struct, defined in a .di file: struct S { private int _c; int c(); void c(int n); } struct S2 { S b(); } Now, in your main file you have: void main() { S2 a; a.b.c = 3; } How in the world is the compiler supposed to know whether to allow this or not?It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible.I think it is eminently possible, but we must figure a solution that doesn't complicate the language all too much.
Jul 29 2009
On Wed, 29 Jul 2009 15:14:04 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:If we have restrictive shit like this where the compiler thinks it knows better than me, can we at least only have it in SafeD? -SteveOn Wed, 29 Jul 2009 14:08:18 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:By making a conservative decision.Steven Schveighoffer wrote:Here is a struct, defined in a .di file: struct S { private int _c; int c(); void c(int n); } struct S2 { S b(); } Now, in your main file you have: void main() { S2 a; a.b.c = 3; } How in the world is the compiler supposed to know whether to allow this or not?It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible.I think it is eminently possible, but we must figure a solution that doesn't complicate the language all too much.
Jul 30 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 15:14:04 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It's a matter of degree. There's already plenty of correct code that D or other languages deem as invalid. So the issue is how conservative the conservative decision would be. AndreiSteven Schveighoffer wrote:If we have restrictive shit like this where the compiler thinks it knows better than me, can we at least only have it in SafeD?On Wed, 29 Jul 2009 14:08:18 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:By making a conservative decision.Steven Schveighoffer wrote:Here is a struct, defined in a .di file: struct S { private int _c; int c(); void c(int n); } struct S2 { S b(); } Now, in your main file you have: void main() { S2 a; a.b.c = 3; } How in the world is the compiler supposed to know whether to allow this or not?It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible.I think it is eminently possible, but we must figure a solution that doesn't complicate the language all too much.
Jul 30 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either... Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.) As for the rest, I'm sure all of you will have figured it out after some more ~500 postings.Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???
Jul 29 2009
On Wed, 29 Jul 2009 14:22:26 -0400, grauzone <none example.net> wrote:Steven Schveighoffer wrote:What I meant was, I wouldn't want something like a.b.c.d.e.f = 3 to generate the equivalent of 25 lines of code.On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either...Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.)option 1, return a ref Point struct option 2, return a special struct which uses properties to set the values in the original widget. I don't think it's an impossible problem to solve, I just don't think the compiler should be involved, because it makes it too easy to gerenate horrible code. Now, having the compiler reject invalid assignments is definitely something I can live with. -Steve
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 14:22:26 -0400, grauzone <none example.net> wrote:So we could have semantics that actually work, but you don't want them because, oh man, my code might have to do a few more assignments. A few assignments. Really?! !!!! Assignments aren't even that expensive! They are one of the easiest operations your CPU can perform! It's like you'll have a few more MOV operations laying around in the worst case. If there are dereferences involved it has to break up the expression ANYWAYS. ARGH! You'll have to forgive me. What I'm reading here is quite frustrating.Steven Schveighoffer wrote:What I meant was, I wouldn't want something like a.b.c.d.e.f = 3 to generate the equivalent of 25 lines of code.On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either...Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.)option 1, return a ref Point struct option 2, return a special struct which uses properties to set the values in the original widget. I don't think it's an impossible problem to solve, I just don't think the compiler should be involved, because it makes it too easy to gerenate horrible code.Now, having the compiler reject invalid assignments is definitely something I can live with. -Steve
Jul 29 2009
Chad J wrote:Steven Schveighoffer wrote:Thinking about it a little more, the extra temporaries could run you out of registers. That still sounds like a negligable cost in most code. As I've mentioned elsewhere, it's also really easy to optimize this by hand if it ever becomes a performance problem.On Wed, 29 Jul 2009 14:22:26 -0400, grauzone <none example.net> wrote:So we could have semantics that actually work, but you don't want them because, oh man, my code might have to do a few more assignments. A few assignments. Really?! !!!! Assignments aren't even that expensive! They are one of the easiest operations your CPU can perform! It's like you'll have a few more MOV operations laying around in the worst case. If there are dereferences involved it has to break up the expression ANYWAYS. ARGH! You'll have to forgive me. What I'm reading here is quite frustrating.Steven Schveighoffer wrote:What I meant was, I wouldn't want something like a.b.c.d.e.f = 3 to generate the equivalent of 25 lines of code.On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either...Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.)option 1, return a ref Point struct option 2, return a special struct which uses properties to set the values in the original widget. I don't think it's an impossible problem to solve, I just don't think the compiler should be involved, because it makes it too easy to gerenate horrible code.Now, having the compiler reject invalid assignments is definitely something I can live with. -Steve
Jul 29 2009
Chad J wrote:Thinking about it a little more, the extra temporaries could run you out of registers. That still sounds like a negligable cost in most code.Temporaries can be on the stack. That's not a problem.
Jul 29 2009
On Wed, Jul 29, 2009 at 1:14 PM, grauzone<none example.net> wrote:Chad J wrote:How is that not a performance issue? The stack is in main memory. --bbThinking about it a little more, the extra temporaries could run you out of registers. =A0That still sounds like a negligable cost in most code.Temporaries can be on the stack. That's not a problem.
Jul 29 2009
Bill Baxter wrote:On Wed, Jul 29, 2009 at 1:14 PM, grauzone<none example.net> wrote:This is where my knowledge starts to run a bit thin. So correct me if I'm wrong, but isn't something like the stack (or at least the top/bottom/end in use) extremely likely to be in the nearest cache (L1)? If that's the case, then this kind of dereference is going to be of the cheaper variety.Chad J wrote:How is that not a performance issue? The stack is in main memory. --bbThinking about it a little more, the extra temporaries could run you out of registers. That still sounds like a negligable cost in most code.Temporaries can be on the stack. That's not a problem.
Jul 29 2009
Chad J wrote:Bill Baxter wrote:Also, really deep dot chains are unlikely to happen. I just feel like this won't create many more memory accesses than there were already. Especially for people with 64 bit OSes on x86_64 that are not register starved like the 32 bit x86. On x86 you are hitting the stack all the time anyways, and the extra access or two will go unnoticed.On Wed, Jul 29, 2009 at 1:14 PM, grauzone<none example.net> wrote:This is where my knowledge starts to run a bit thin. So correct me if I'm wrong, but isn't something like the stack (or at least the top/bottom/end in use) extremely likely to be in the nearest cache (L1)? If that's the case, then this kind of dereference is going to be of the cheaper variety.Chad J wrote:How is that not a performance issue? The stack is in main memory. --bbThinking about it a little more, the extra temporaries could run you out of registers. That still sounds like a negligable cost in most code.Temporaries can be on the stack. That's not a problem.
Jul 29 2009
Chad J wrote:Chad J wrote:Especially especially because, if you prevent the a.b.c = x syntax, the only thing that'll happen is you'll cause people to write all that code themselves. The same number of assignments will happen anyhow, but the user will have to write them all manually. I'll all for having the compiler automate the boilerplate stuff. Also, note that the double-assignment case only happens when assigning to value types. Assigning to reference type properties will be unaffected. --benjiBill Baxter wrote:Also, really deep dot chains are unlikely to happen. I just feel like this won't create many more memory accesses than there were already. Especially for people with 64 bit OSes on x86_64 that are not register starved like the 32 bit x86. On x86 you are hitting the stack all the time anyways, and the extra access or two will go unnoticed.On Wed, Jul 29, 2009 at 1:14 PM, grauzone<none example.net> wrote:This is where my knowledge starts to run a bit thin. So correct me if I'm wrong, but isn't something like the stack (or at least the top/bottom/end in use) extremely likely to be in the nearest cache (L1)? If that's the case, then this kind of dereference is going to be of the cheaper variety.Chad J wrote:How is that not a performance issue? The stack is in main memory. --bbThinking about it a little more, the extra temporaries could run you out of registers. That still sounds like a negligable cost in most code.Temporaries can be on the stack. That's not a problem.
Jul 30 2009
On Wed, 29 Jul 2009 15:01:47 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:Steven Schveighoffer wrote:Hold on a second, don't we already have semantics that work? I mean we can already write auto tmp = a.b; tmp.c = 5; a.b = tmp; So what is the big deal? If your widget.position is a struct with fields, then the compiler should be able to detect the error (not yet?) and tell you "no, it's an rvalue." Why should the compiler make assumptions about the logic of code when they may be incorrect, and might be better optimized by a person? I would think that macros would be a better fit for this.On Wed, 29 Jul 2009 14:22:26 -0400, grauzone <none example.net> wrote:So we could have semantics that actually work, but you don't want them because, oh man, my code might have to do a few more assignments. A few assignments. Really?!Steven Schveighoffer wrote:What I meant was, I wouldn't want something like a.b.c.d.e.f = 3 to generate the equivalent of 25 lines of code.On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either...Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.)option 1, return a ref Point struct option 2, return a special struct which uses properties to set the values in the original widget. I don't think it's an impossible problem to solve, I just don't think the compiler should be involved, because it makes it too easy to gerenate horrible code.Assignments aren't even that expensive! They are one of the easiest operations your CPU can perform! It's like you'll have a few more MOV operations laying around in the worst case.It's not the assignments, its the idea that the compiler should workaround the poor design of the code by writing possibly incorrect code. I'd rather be in charge of the design of my code, thanks. If the compiler help prevent me from making obvious *provable* mistakes, then fine. If it makes decisions that might be based on incomplete information, I don't want that. -Steve
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 15:01:47 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:Ah, well that argument has some weight. I'd like to know though, what assumptions does this make about the code? Why might they be incorrect? Those are not rhetorical questions. Just to be clear, I acknowledge that me saying "it is unlikely to produce incorrect code" is a poor argument for a feature. My intent here is to find out what exactly is wrong with the proposed transformation. If the compiler /knows/ that something being used is a property, I just don't understand how that information is incomplete. Also macros aren't a good fit for this because they aren't going to exist in D2, or necessarily ever. Well, properties may not pop up in D2 either, but if they're going to happen it'd be nicer if they did.So we could have semantics that actually work, but you don't want them because, oh man, my code might have to do a few more assignments. A few assignments. Really?!Hold on a second, don't we already have semantics that work? I mean we can already write auto tmp = a.b; tmp.c = 5; a.b = tmp; So what is the big deal? If your widget.position is a struct with fields, then the compiler should be able to detect the error (not yet?) and tell you "no, it's an rvalue." Why should the compiler make assumptions about the logic of code when they may be incorrect, and might be better optimized by a person? I would think that macros would be a better fit for this.Assignments aren't even that expensive! They are one of the easiest operations your CPU can perform! It's like you'll have a few more MOV operations laying around in the worst case.It's not the assignments, its the idea that the compiler should workaround the poor design of the code by writing possibly incorrect code. I'd rather be in charge of the design of my code, thanks. If the compiler help prevent me from making obvious *provable* mistakes, then fine. If it makes decisions that might be based on incomplete information, I don't want that. -Steve
Jul 29 2009
Chad J Wrote:Currently there are some cases where the current paradigm forces you to do that kind of work by hand: struct Rectangle { float x,y,w,h; } class Widget { Rectangle _rect; Rectangle rect() { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } } void main() { auto widget = new Widget(); // DOES WORK: auto tmp = widget.rect; tmp.w = 200; tmp.h = 100; widget.rect = tmp; // DOES NOT WORK: // widget.rect.w = 200; // widget.rect.h = 100; }What about: class Widget { Rectangle _rect; immutable(Rectangle) rect() const { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } }
Jul 29 2009
Zhenyu Zhou wrote:What about: class Widget { Rectangle _rect; immutable(Rectangle) rect() const { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } }You'll fall into the trap unless you know about immutable. Said another way: the default is unsafe. Also this still isn't very useful, as it still requires the calling programmer to manually break apart the accesses and will not work for things like "array.length++;" which were errors already. So even if newbies were omniscient and always made their getters immutable, all you'd have accomplished is turning a debugging session into an annoyance. Noble, but all too bitter when a complete solution is within grasp. This is also conflating the problem with rvalues-in-lhs with the issue of D's lack of properties. Forbidding assignment and mutation of rvalues eliminates the debugging session. The annoyance of "why won't this work?!", well, that is for properties to solve. See: http://d.puremagic.com/issues/show_bug.cgi?id=3008
Jul 29 2009
Chad J Wrote:Zhenyu Zhou wrote:Maybe this is what you want ref rect() { return _rect; } But I would still return const type because it's unsafe to change the rect without calling its setter e.g. Rectangle rect(Rectangle r) { _rect = r; redraw(); return _rect; } If you allow widget.rect.w = 200; widget.rect.h = 100; you will have to write much more code to handle the painting correctly. and we don't want to call redraw twice hereWhat about: class Widget { Rectangle _rect; immutable(Rectangle) rect() const { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } }You'll fall into the trap unless you know about immutable. Said another way: the default is unsafe. Also this still isn't very useful, as it still requires the calling programmer to manually break apart the accesses and will not work for things like "array.length++;" which were errors already. So even if newbies were omniscient and always made their getters immutable, all you'd have accomplished is turning a debugging session into an annoyance. Noble, but all too bitter when a complete solution is within grasp.
Jul 29 2009
Zhenyu Zhou wrote:Chad J Wrote:The point is to make sure that when a property's member appears on the left-hand-side of an assign expression, the setter will be called. All this is doing is outright forbidding the property's member to appear on the left-hand-side of an assign expression at all. It's a step in the right direction, but we can do better. (Some of what I said there is probably wrong at a technical level, but I'm trying to be clear and not pedantic.)Zhenyu Zhou wrote:Maybe this is what you want ref rect() { return _rect; } But I would still return const type because it's unsafe to change the rect without calling its setterWhat about: class Widget { Rectangle _rect; immutable(Rectangle) rect() const { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } }You'll fall into the trap unless you know about immutable. Said another way: the default is unsafe. Also this still isn't very useful, as it still requires the calling programmer to manually break apart the accesses and will not work for things like "array.length++;" which were errors already. So even if newbies were omniscient and always made their getters immutable, all you'd have accomplished is turning a debugging session into an annoyance. Noble, but all too bitter when a complete solution is within grasp.e.g. Rectangle rect(Rectangle r) { _rect = r; redraw(); return _rect; } If you allow widget.rect.w = 200; widget.rect.h = 100; you will have to write much more code to handle the painting correctly. and we don't want to call redraw twice heremeh, it's not going to cost anything to resize until the next frame is rendered anyways ;) Widgets and Rectangles are just an arbitrary example used to show where people can get trapped by the language's misfeature. Solving this only for Widgets and Rectangles will, well, only do that much, and thus be a waste of time since we've already acknowledged the problem and know how to hack around it in existing code.
Jul 30 2009
"Zhenyu Zhou" <rinick gmail.com> wrote in message news:h4rfif$2os2$1 digitalmars.com...e.g. Rectangle rect(Rectangle r) { _rect = r; redraw(); return _rect; } If you allow widget.rect.w = 200; widget.rect.h = 100; you will have to write much more code to handle the painting correctly. and we don't want to call redraw twice herewrite code such as the above, it's very clear that you're changing the rect twice. If that's a problem, you just do this: widget.rect = Rect(200, 100); Easy.
Jul 30 2009
On Thu, 30 Jul 2009 14:09:06 -0400, Nick Sabalausky <a a.a> wrote:"Zhenyu Zhou" <rinick gmail.com> wrote in message news:h4rfif$2os2$1 digitalmars.com...Rect has 4 values (x, y, width, height), otherwise, the example doesn't make much sense. -Stevee.g. Rectangle rect(Rectangle r) { _rect = r; redraw(); return _rect; } If you allow widget.rect.w = 200; widget.rect.h = 100; you will have to write much more code to handle the painting correctly. and we don't want to call redraw twice hereyou write code such as the above, it's very clear that you're changing the rect twice. If that's a problem, you just do this: widget.rect = Rect(200, 100);
Jul 30 2009
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.uxv7r6ndeav7ka localhost.localdomain...On Thu, 30 Jul 2009 14:09:06 -0400, Nick Sabalausky <a a.a> wrote:I've dealt with that as well, and done both of these (though not at the same time obviously ;) ): - widget.rect = Rect(widget.rect.x, widget.rect.y, 200, 100); - Cache the reference manually. So still easy."Zhenyu Zhou" <rinick gmail.com> wrote in message news:h4rfif$2os2$1 digitalmars.com...Rect has 4 values (x, y, width, height), otherwise, the example doesn't make much sense.e.g. Rectangle rect(Rectangle r) { _rect = r; redraw(); return _rect; } If you allow widget.rect.w = 200; widget.rect.h = 100; you will have to write much more code to handle the painting correctly. and we don't want to call redraw twice hereyou write code such as the above, it's very clear that you're changing the rect twice. If that's a problem, you just do this: widget.rect = Rect(200, 100);
Jul 30 2009
Nick Sabalausky wrote:"Zhenyu Zhou" <rinick gmail.com> wrote in message news:h4rfif$2os2$1 digitalmars.com...It's kind of a moot point anyhow, because most respectable graphics frameworks will defer any rendering until all properties have been set. Something like this: class Rect { private int _w; private int _h; private boolean _dirty; property set w(int value) { _w = value; _dirty = true; } property set h(int value) { _h = value; _dirty = true; } void draw() { if (_dirty) { // rendering code _dirty = false; } } } Rendering code is *never* invoked from within a property-setter, and property values are never changed during rendering code. (Also, there's usually a separate "measurement" phase, following the manual property-setting phase, within which properties can be changed to suit the positional constraints but where no rendering occurs.) Anyhow, I think those kinds of considerations are mostly orthogonal to a discussion of properties, in the general sense, except insofar as the existence of a property syntax makes it more convenient to implement things like dirty-flag marking, property-change listeners, and the like. --benjie.g. Rectangle rect(Rectangle r) { _rect = r; redraw(); return _rect; } If you allow widget.rect.w = 200; widget.rect.h = 100; you will have to write much more code to handle the painting correctly. and we don't want to call redraw twice herewrite code such as the above, it's very clear that you're changing the rect twice. If that's a problem, you just do this: widget.rect = Rect(200, 100); Easy.
Jul 30 2009
On Wed, 29 Jul 2009 18:27:09 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:Steven Schveighoffer wrote:Simply that the compiler assumes it's simply setting a value. However, setters are functions and can execute any code they wish. You may get into weird states that you don't want to or perform unneeded actions that you aren't expecting. The example given later in this thread is perfect -- setting the width and height individually may re-render the widget when you only should re-render once. Another example is something like this: class C { int x; } struct S { C c; } struct S2 { C c; S s() { return S(c); } void s(S s) {c = s.c;} } void main() { S2 s2; s2.c = new C; s2.s.c.x = 5; } If the compiler rewrites that last line as: auto tmp = s2.s; s2.c.x = 5; s2.s = tmp; Then it is completely unnecessary, and could cause problems if the setter does something else besides setting.On Wed, 29 Jul 2009 15:01:47 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:Ah, well that argument has some weight. I'd like to know though, what assumptions does this make about the code? Why might they be incorrect?So we could have semantics that actually work, but you don't want them because, oh man, my code might have to do a few more assignments. A few assignments. Really?!Hold on a second, don't we already have semantics that work? I mean we can already write auto tmp = a.b; tmp.c = 5; a.b = tmp; So what is the big deal? If your widget.position is a struct with fields, then the compiler should be able to detect the error (not yet?) and tell you "no, it's an rvalue." Why should the compiler make assumptions about the logic of code when they may be incorrect, and might be better optimized by a person? I would think that macros would be a better fit for this.Assignments aren't even that expensive! They are one of the easiest operations your CPU can perform! It's like you'll have a few more MOV operations laying around in the worst case.It's not the assignments, its the idea that the compiler should workaround the poor design of the code by writing possibly incorrect code. I'd rather be in charge of the design of my code, thanks. If the compiler help prevent me from making obvious *provable* mistakes, then fine. If it makes decisions that might be based on incomplete information, I don't want that. -SteveIf the compiler /knows/ that something being used is a property, I just don't understand how that information is incomplete.First, because the problem of determining what code does is an NP-complete problem -- the compiler can't know what code is going to do except by running it. It's just like trying to write a program that detects infinite loops. So it must make some assumptions. Second, because D allows opaque function declarations, so the compiler might not even be able to *look* at what a property does. It can only assume, and the assumption you would have it make is that a property is a simple setter that has no other side effects.Also macros aren't a good fit for this because they aren't going to exist in D2, or necessarily ever. Well, properties may not pop up in D2 either, but if they're going to happen it'd be nicer if they did.I think you can solve this problem (and solve it correctly) with some sort of fancy template magic, but not without some extra baggage (such as an extra type that might not be optimized). I envision something like this: with(Setter!(widget.location)) // don't know if this works { width = 50; height = 100; // at scope end, Setter sets widget.location to it's internal representation via a finalizer } The reason I said macros is because they have the power to rewrite the code exactly like you said the compiler should. At least with a macro you would have some indication that it is exactly what the user wants, and you can have the power to do your optimizations. -Steve
Jul 30 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 18:27:09 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:That's a problem of library design and code architecture, nothing inherent in properties. You can make such mistakes using functions as well. The mistake here is not so much the multiple calls into the widget, but the fact that multiple calls would redraw the widget multiple times - bad! That thing should wait until the entire screen is redrawn. There are data types where changes to state are expensive. They tend to be designed with the ability to queue up changes and execute them all at once. Whether the changes are done with functions or properties would not matter.I'd like to know though, what assumptions does this make about the code? Why might they be incorrect?Simply that the compiler assumes it's simply setting a value. However, setters are functions and can execute any code they wish. You may get into weird states that you don't want to or perform unneeded actions that you aren't expecting. The example given later in this thread is perfect -- setting the width and height individually may re-render the widget when you only should re-render once.Another example is something like this: class C { int x; } struct S { C c; } struct S2 { C c; S s() { return S(c); } void s(S s) {c = s.c;} } void main() { S2 s2; s2.c = new C; s2.s.c.x = 5; } If the compiler rewrites that last line as: auto tmp = s2.s; s2.c.x = 5; s2.s = tmp;I think there's a typo. auto tmp = s2.s; tmp.c.x = 5; s2.s = tmp; I'm going to assume that's what you meant.Then it is completely unnecessary, and could cause problems if the setter does something else besides setting.I'm not quite sure I follow. I'm reading the first bit as, "if I write code just like so, then 's2.s.c.x = 5;' will generate extra code because 's2.s.c.x = 5;' works fine without the rewrite." A true statement. I don't see how it relates to setters doing other things. Setters don't have to be written like that, and they can do other perfectly useful things that won't cause any problems. The setter can execute arbitrary code. Of course it can cause problems! Programmers aren't going to make it cause problems though.I never suggested analyzing the code. The implication is that the definition contains information telling the compiler that it is a property getter/setter. Assuming the properties don't have side effects is also a bad idea. Side effects are one of the big uses of properties. They allow you to set dirty-flags, increment/decrement counters, lazily allocate memory, call events, and do any number of nifty things. Functions let you do those nifty things too, but if you have an existing API that has fields, you can't use functions without breaking API changes. However, you can migrate the fields to properties without breaking user code and then reap the benefits of functions without using functions. Not to mention the bonus in being able to make the API's intent more clear (that whole verb vs noun thing). Like many features, properties can be used to do bad things. The important thing is that the programmer must be very intentional to accomplish said bad things. Using properties correctly is very easy and natural. (Note that I don't consider D's current properties to actually be properties. Omissible parentheses is a better name.) In the Widget/Rectangle example, properties can be used to set dirty flags whenever the rectangle is modified. Now the GUI library knows exactly which Widgets have changed and which haven't, and all without having to diff against previous state. This information can be used to only modify the pixels over places where widgets changed. This example is somewhat fictitious though, since that optimization doesn't bring you many gains with today's GPUs. Still, it does hint at the usefulness of monitoring changes in state. Currently the only way to do this in a complete and *future-proof* manner is to use interfaces that expose only functions. Some people seem perfectly happy with that, but I dislike how it tends to cause code bloat (SLoC mostly) and terrible violations of DRY. The lack of nouns is a little annoying too.If the compiler /knows/ that something being used is a property, I just don't understand how that information is incomplete.First, because the problem of determining what code does is an NP-complete problem -- the compiler can't know what code is going to do except by running it. It's just like trying to write a program that detects infinite loops. So it must make some assumptions. Second, because D allows opaque function declarations, so the compiler might not even be able to *look* at what a property does. It can only assume, and the assumption you would have it make is that a property is a simple setter that has no other side effects.That seems to solve a different problem. That might actually be an interesting trick. I'll have to try and use it some time. Properties are often used for doing bookkeeping on the callee's side, so requiring the caller to do a bunch of bookkeeping defeats the purpose.Also macros aren't a good fit for this because they aren't going to exist in D2, or necessarily ever. Well, properties may not pop up in D2 either, but if they're going to happen it'd be nicer if they did.I think you can solve this problem (and solve it correctly) with some sort of fancy template magic, but not without some extra baggage (such as an extra type that might not be optimized). I envision something like this: with(Setter!(widget.location)) // don't know if this works { width = 50; height = 100; // at scope end, Setter sets widget.location to it's internal representation via a finalizer }The reason I said macros is because they have the power to rewrite the code exactly like you said the compiler should. At least with a macro you would have some indication that it is exactly what the user wants, and you can have the power to do your optimizations. -SteveMy issue with macros isn't a lack of capability, but rather a lack of existence ;)
Jul 31 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 14:22:26 -0400, grauzone <none example.net> wrote:The thing above was just the consequence of Daniel Keep's idea of writing back those modified temporary values. In the common case, you wouldn't use such deep nesting anyway.Steven Schveighoffer wrote:What I meant was, I wouldn't want something like a.b.c.d.e.f = 3 to generate the equivalent of 25 lines of code.On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either...Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???Then I can it make just a field. The reason that one makes this a property are: 1. Want to catch writes with a getter. 2. Wants to make it read-only (you had to return a const reference, which probably would make the implementation of Point a bit annoying: you had to mark methods as const etc.)Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.)option 1, return a ref Point structoption 2, return a special struct which uses properties to set the values in the original widget.Now this would generate a mess (lots of bloat). Now I'm not sure; maybe macros could provide a way out (auto generate the code bloat), or possibly you could use alias this to properly "wrap" a value? Any ideas on this?I don't think it's an impossible problem to solve, I just don't think the compiler should be involved, because it makes it too easy to gerenate horrible code. Now, having the compiler reject invalid assignments is definitely something I can live with.This would be better than the status quo, yes.-Steve
Jul 29 2009
grauzone wrote:Steven Schveighoffer wrote:Just say no. It is far easier to optimize the nesting assignments. It is also easy to optimize the nesting assignments by hand if it's really necessary. Not to mention if you don't optimize the nesting assignments at all, they are still orders of magnitude faster than this sort of thing, and only slightly slower than optimal code. What worries me more about this is things like type casting and the unary ++ the special struct may be expected to overload. This is the case in something like "array.length++;". length would return a proxy struct that would have to: 1) be implicity castable to size_t 2) overload opPostInc, opPostDec, opXxxAssign, and opAssign. That's a lot of DRY violation and tedium. You have to do it for every property that sets a calculated value.option 2, return a special struct which uses properties to set the values in the original widget.Now this would generate a mess (lots of bloat). Now I'm not sure; maybe macros could provide a way out (auto generate the code bloat), or possibly you could use alias this to properly "wrap" a value? Any ideas on this?
Jul 29 2009
grauzone wrote:Steven Schveighoffer wrote:But you don't /have/ to type out that mess! Why would anyone do that?! It's madness. The compiler does it FOR you. That's why it's there. It is supposed to save you from doing tedious work. Currently there are some cases where the current paradigm forces you to do that kind of work by hand: struct Rectangle { float x,y,w,h; } class Widget { Rectangle _rect; Rectangle rect() { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } // etc } void main() { auto widget = new Widget(); // DOES WORK: auto tmp = widget.rect; tmp.w = 200; tmp.h = 100; widget.rect = tmp; // DOES NOT WORK: // widget.rect.w = 200; // widget.rect.h = 100; }On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either... Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.) As for the rest, I'm sure all of you will have figured it out after some more ~500 postings.Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???
Jul 29 2009
On Wed, 29 Jul 2009 14:46:11 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:grauzone wrote:Wouldn't the compiler write: //widget.rect.w = 200 translates to auto tmp1 = widget.rect; tmp1.w = 200; widget.rect = tmp1; //widget.rect.h = 100 translates to auto tmp2 = widget.rect; tmp2.h = 100; widget.rect = tmp2; ??? Unless you want some serious optimization requirements... -SteveSteven Schveighoffer wrote:But you don't /have/ to type out that mess! Why would anyone do that?! It's madness. The compiler does it FOR you. That's why it's there. It is supposed to save you from doing tedious work. Currently there are some cases where the current paradigm forces you to do that kind of work by hand: struct Rectangle { float x,y,w,h; } class Widget { Rectangle _rect; Rectangle rect() { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } // etc } void main() { auto widget = new Widget(); // DOES WORK: auto tmp = widget.rect; tmp.w = 200; tmp.h = 100; widget.rect = tmp; // DOES NOT WORK: // widget.rect.w = 200; // widget.rect.h = 100; }On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either... Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.) As for the rest, I'm sure all of you will have figured it out after some more ~500 postings.Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 14:46:11 -0400, Chad J <chadjoan __spam.is.bad__gmail.com> wrote:It would. The optimization you speak of is reference caching. I often do it by hand in deeply nested loops where it actually means a damn. It's also an optimization I think compilers should do, because it is useful in many more cases than just this. Using some manner of property syntax would not preclude the programmer from writing the optimized version of the code by hand.grauzone wrote:Wouldn't the compiler write: //widget.rect.w = 200 translates to auto tmp1 = widget.rect; tmp1.w = 200; widget.rect = tmp1; //widget.rect.h = 100 translates to auto tmp2 = widget.rect; tmp2.h = 100; widget.rect = tmp2; ??? Unless you want some serious optimization requirements... -SteveSteven Schveighoffer wrote:But you don't /have/ to type out that mess! Why would anyone do that?! It's madness. The compiler does it FOR you. That's why it's there. It is supposed to save you from doing tedious work. Currently there are some cases where the current paradigm forces you to do that kind of work by hand: struct Rectangle { float x,y,w,h; } class Widget { Rectangle _rect; Rectangle rect() { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } // etc } void main() { auto widget = new Widget(); // DOES WORK: auto tmp = widget.rect; tmp.w = 200; tmp.h = 100; widget.rect = tmp; // DOES NOT WORK: // widget.rect.w = 200; // widget.rect.h = 100; }On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:I don't want to type out that mess as a user either... Design changes to avoid that mentioned mess would interfere with the goal of abstraction (e.g. assume you have widget.position, now how do you set only the x coordinate? yeah, split the property into position_x and position_y. Result is you have more noise, and you can't use a Point struct.) As for the rest, I'm sure all of you will have figured it out after some more ~500 postings.Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???
Jul 29 2009
Chad J wrote:Steven Schveighoffer wrote:I should probably explain this more. Suppose you have some data structure in memory. struct Foo { Bar* a; } struct Bar { float[] thingies; } Then you have a Foo and you need to stroke it's Bar's thingies. Foo f; // ... for ( int i = 0; i < f.a.thingies.length; i++ ) stroke(f.a.thingies[i]); Bad bad bad! For every thingie stroked there is going to be two whole dereferences. That's if the compiler was smart enough to move "f.a.thingies.length" outside of the loop. Otherwise it's more like 3 derefences. Unlike mere assignments, those can be expensive, especially if you have a cache miss. 3 of those. Ouch. So rewrite the code like this: Foo f; // ... var things = f.a.thingies; // The reference is now cached. var len = things.length; for ( int i = 0; i < len; i++ ) stroke(things[i]); Ah, much better. Only does 1 dereference per thing ever.Wouldn't the compiler write: //widget.rect.w = 200 translates to auto tmp1 = widget.rect; tmp1.w = 200; widget.rect = tmp1; //widget.rect.h = 100 translates to auto tmp2 = widget.rect; tmp2.h = 100; widget.rect = tmp2; ??? Unless you want some serious optimization requirements... -SteveIt would. The optimization you speak of is reference caching. I often do it by hand in deeply nested loops where it actually means a damn. It's also an optimization I think compilers should do, because it is useful in many more cases than just this.
Jul 29 2009
Chad J wrote:Steven Schveighoffer wrote:And, in fact, this exact kind of optimization is made very simple if the compiler uses a static single assignment (SSA) form for its internal code representation. The LLVM suite already does it. --benjiIt would. The optimization you speak of is reference caching. I often do it by hand in deeply nested loops where it actually means a damn. It's also an optimization I think compilers should do, because it is useful in many more cases than just this. Using some manner of property syntax would not preclude the programmer from writing the optimized version of the code by hand.struct Rectangle { float x,y,w,h; } class Widget { Rectangle _rect; Rectangle rect() { return _rect; } Rectangle rect(Rectangle r) { return _rect = r; } // etc } void main() { auto widget = new Widget(); // DOES WORK: auto tmp = widget.rect; tmp.w = 200; tmp.h = 100; widget.rect = tmp; // DOES NOT WORK: // widget.rect.w = 200; // widget.rect.h = 100; }Wouldn't the compiler write: //widget.rect.w = 200 translates to auto tmp1 = widget.rect; tmp1.w = 200; widget.rect = tmp1; //widget.rect.h = 100 translates to auto tmp2 = widget.rect; tmp2.h = 100; widget.rect = tmp2; ??? Unless you want some serious optimization requirements... -Steve
Jul 30 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 10:16:33 -0400, grauzone <none example.net> wrote:!!! Wait, just what is wrong here? I mean, so what. That expression would generate a lot of code if the compiler were completely naive about this. It might run slightly slower. But, it's probably pretty easy for the compiler to prove that this doesn't need to happen in common cases (e.g. all members are fields). Also, having 5 dotOps in a row like that is very uncommon. If you are worried about speed than cache your dereferences. It's a common trick. I still don't see how we can't do this in a very mechanical manner.Daniel Keep wrote:Yeah, I think this idea is no good. a.b.c.d.e.f = 3, results in one gigantic mess, which the user might not want.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.Yes! At least that's what the user wants. The compiler has to detect, that the object was modified at all. (To know whether it should generate code to write back the property.) Would this make the compiler much complexer? You also have to deal with nested properties: a.b.c.d = 3; turns to auto t = a.b; auto t2 = t.c; c.d = 3; t.c = t2; a.b = t; ???Properties don't have to be exactly like fields. I think we need to get away from that idea. It would be nice if the compiler could help by simply rejecting what it can reject (assignment to rvalues), but other than that, there's not much that can be done. This can be detected in simple cases, but in the case where the end point is a function, it will be difficult or impossible. I don't believe the problem needs to be solved. -SteveThere are a lot of problems that don't /need/ to be solved but /should/ be solved.
Jul 29 2009
Wed, 29 Jul 2009 13:39:50 +1000, Daniel Keep wrote:Walter Bright wrote:vote++ Though I'm not sure what to do with this: void foo(ref int x) { x++; } foo(a.b.c); Probably it's not that hard anyway. Perhaps it's enough to rewrite property access every time a value-returning property is used as lvalue: auto t = a.b; foo(t.c); a.b = t;The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Maybe the compiler could rewrite the above as: auto t = a.b; t.c = 3; a.b = t; Unless it can prove it doesn't need to. Same solution as to the op= conundrum.
Jul 29 2009
On Tue, Jul 28, 2009 at 10:33 PM, Walter Bright<newshound1 digitalmars.com> wrote:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3?So, the issue is that 'a.b()' returns a struct by value. Such return values should always be considered rvalues. Furthermore, 'rvalue.field' should also only yield an rvalue. Therefore, 'a.b.c = 3' should be flagged by the compiler as being as nonsensical as "5 = x". The compiler would flag this as an error, and the solution would of course be to make a.b's return value by reference instead.
Jul 28 2009
Jarrett Billingsley wrote:On Tue, Jul 28, 2009 at 10:33 PM, Walter Bright<newshound1 digitalmars.com> wrote:Problem: what if .b is computed? Take .length as an example; the setter MUST be invoked when the length changes, or the stored value won't have any bearing on the actual number of elements being stored. Returning refs only works if the property is just pretending to be a field; in which case the correct solution is to use a field. Unless it's a property in a class as required by an interface, but you can't make that ref either because then your interface is dictating implementation. :PThe issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3?So, the issue is that 'a.b()' returns a struct by value. Such return values should always be considered rvalues. Furthermore, 'rvalue.field' should also only yield an rvalue. Therefore, 'a.b.c = 3' should be flagged by the compiler as being as nonsensical as "5 = x". The compiler would flag this as an error, and the solution would of course be to make a.b's return value by reference instead.
Jul 28 2009
On Wed, Jul 29, 2009 at 1:08 AM, Daniel Keep<daniel.keep.lists gmail.com> w= rote:Jarrett Billingsley wrote:hatOn Tue, Jul 28, 2009 at 10:33 PM, Walter Bright<newshound1 digitalmars.com> wrote:The issue is what if b is a property, returns a temporary object, and t==3Dtemp's .c field is uselessly set to 3?So, the issue is that 'a.b()' returns a struct by value. =A0Such return values should always be considered rvalues. =A0Furthermore, 'rvalue.field' should also only yield an rvalue. =A0Therefore, 'a.b.c =r3' should be flagged by the compiler as being as nonsensical as "5 =3D x". The compiler would flag this as an error, and the solution would of course be to make a.b's return value by reference instead.Problem: what if .b is computed? =A0Take .length as an example; the sette=MUST be invoked when the length changes, or the stored value won't have any bearing on the actual number of elements being stored.That's not the issue at hand. The issue is that the compiler accepts no-effect modifications of temporary values as valid statements. There is no setter being invoked here, nor should there be. Or should there? In the face of a value type, should the compiler rewrite this code as auto t =3D a.b(); t.c =3D 3; a.b =3D t; ? The last line of the rewrite is unnecessary if a.b() returns a reference type or a byref struct. But is this what people would expect to happen?Returning refs only works if the property is just pretending to be a field; in which case the correct solution is to use a field.Not entirely; you can (for some value of 'can') return a struct that has overloaded opAssign to do nontrivial setters. But that's kludgey and C++-y.
Jul 29 2009
Jarrett Billingsley wrote:The issue is that the compiler accepts no-effect modifications of temporary values as valid statements. There is no setter being invoked here, nor should there be. Or should there? In the face of a value type, should the compiler rewrite this code as auto t = a.b(); t.c = 3; a.b = t; ? The last line of the rewrite is unnecessary if a.b() returns a reference type or a byref struct. But is this what people would expect to happen?I think the compiler should only rewrite the code (as above) if a.b() returns a struct, by value. The compiler can figure that out easily enough. Depending on the return types of all the different properties in a.b.c.d.e.f = 3, there might be a few ref types and a few value types returned. Each of those subexpressions would be rewritten with the appropriate semantics. --benji
Jul 30 2009
Jarrett Billingsley wrote:On Wed, Jul 29, 2009 at 1:08 AM, Daniel Keep<daniel.keep.lists gmail.com> wrote:I believe it is. Note what happens if the user doesn't expect this: Rather than the reference being set to the correct value, the reference is set to the correct value. Seems fine to me. The only issue I see as being potentially bad is that if the coder doesn't know about the rewrite rule and writes a non-trivial setter that assumes that the incoming reference never was the outgoing reference. It's kind of an odd assumption, and one that's bound to fail in other cases too (where other cases is any time the caller explicitly reads from the property and then ... and then writes the original back into it).Problem: what if .b is computed? Take .length as an example; the setter MUST be invoked when the length changes, or the stored value won't have any bearing on the actual number of elements being stored.That's not the issue at hand. The issue is that the compiler accepts no-effect modifications of temporary values as valid statements. There is no setter being invoked here, nor should there be. Or should there? In the face of a value type, should the compiler rewrite this code as auto t = a.b(); t.c = 3; a.b = t; ? The last line of the rewrite is unnecessary if a.b() returns a reference type or a byref struct. But is this what people would expect to happen?Yeah. Does not want.Returning refs only works if the property is just pretending to be a field; in which case the correct solution is to use a field.Not entirely; you can (for some value of 'can') return a struct that has overloaded opAssign to do nontrivial setters. But that's kludgey and C++-y.
Jul 31 2009
Walter Bright Wrote:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions.Does this problem pertain to properties? Look at this: void main() { int a=3; } Is "a" assigned usefully or uselessly? And what compiler says about it? And how did you determine that your example is useless? Did you check for destructors, invariants, copy constructors? And do your question imply that functions are allowed to return temporaries while properties aren't? And what's the difference if c is field or property?
Jul 29 2009
Kagamin wrote:Walter Bright Wrote:The code above is only loosely related. The code above contains a definition initiated by the user. The code a.b.c = 4 expresses the intent of a user to effect a change a field that can be accessed later through a.b.c, whereas with properties the code will in all likelihood not do that.The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions.Does this problem pertain to properties? Look at this: void main() { int a=3; } Is "a" assigned usefully or uselessly? And what compiler says about it? And how did you determine that your example is useless? Did you check for destructors, invariants, copy constructors?And do your question imply that functions are allowed to return temporaries while properties aren't?The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?And what's the difference if c is field or property?It's b that's the problem. Andrei
Jul 29 2009
Andrei Alexandrescu Wrote:The code above is only loosely related. The code above contains a definition initiated by the user.True, but is there any technical difference for compiler? How the usefulness of the code change depending on whether it's written by the user or... huh?.. don't know what is the alternative...The code a.b.c = 4 expresses the intent of a user to effect a change a field that can be accessed later through a.b.c, whereas with properties the code will in all likelihood not do that.That's idealistic view of things. A programmer's imagination used to be more inventive :)The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.So do you attempt to dictate how library designers should implement their types, whether they should use value types or reference types? More important, are you trying to say that property is not allowed to return std.typecons.Unique since it's a value type?And what's the difference if c is field or property?It's b that's the problem.
Jul 29 2009
Kagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff. AndreiThe question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
Andrei Alexandrescu Wrote:Kagamin wrote:interfaces, inheritance, value types, but never - this thing.Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
Kagamin wrote:Andrei Alexandrescu Wrote:can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
On Wed, 29 Jul 2009 18:36:07 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Kagamin wrote:I believe you can still return a struct from an object via property.Andrei Alexandrescu Wrote:can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
Andrei Alexandrescu wrote:Kagamin wrote:to what Walter proposed). --- public class Bar { public Foo Foo { get; set; } } public struct Foo { public int Property { get; set; } } Bar bar = new Bar(); Foo foo = new Foo(); foo.Property = 10; bar.Foo = foo; bar.Foo.Property = 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it is not a variableAndrei Alexandrescu Wrote:can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
On Wed, Jul 29, 2009 at 10:44 AM, Ary Borenszweig<ary esperanto.org.ar> wro= te:Andrei Alexandrescu wrote:oKagamin wrote:Andrei Alexandrescu Wrote:can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c =3D 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c =3D 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.what Walter proposed). --- public class Bar { =A0 =A0public Foo Foo { get; set; } } public struct Foo { =A0 =A0public int Property { get; set; } } Bar bar =3D new Bar(); Foo foo =3D new Foo(); foo.Property =3D 10; bar.Foo =3D foo; bar.Foo.Property =3D 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it =isnot a variableBooom, exactly what I said about rvalues.
Jul 29 2009
On Wed, Jul 29, 2009 at 9:23 AM, Jarrett Billingsley<jarrett.billingsley gmail.com> wrote:On Wed, Jul 29, 2009 at 10:44 AM, Ary Borenszweig<ary esperanto.org.ar> w=rote:sAndrei Alexandrescu wrote:Kagamin wrote:Andrei Alexandrescu Wrote:Kagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c =3D 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c =3D 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.tocan't define properties. Andreiiswhat Walter proposed). --- public class Bar { =A0 =A0public Foo Foo { get; set; } } public struct Foo { =A0 =A0public int Property { get; set; } } Bar bar =3D new Bar(); Foo foo =3D new Foo(); foo.Property =3D 10; bar.Foo =3D foo; bar.Foo.Property =3D 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it=Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c =3D 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not. --bbnot a variableBooom, exactly what I said about rvalues.
Jul 29 2009
Bill Baxter wrote:On Wed, Jul 29, 2009 at 9:23 AM, Jarrett Billingsley<jarrett.billingsley gmail.com> wrote:Probably Walter means a.b.c = 3; // b is a field works, while a.b.c = 3; // b is a getter is a useless call. Nevertheless, if b() uses ref-return then it is meaningful.On Wed, Jul 29, 2009 at 10:44 AM, Ary Borenszweig<ary esperanto.org.ar> wrote:Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not. --bbAndrei Alexandrescu wrote:Booom, exactly what I said about rvalues.Kagamin wrote:what Walter proposed). --- public class Bar { public Foo Foo { get; set; } } public struct Foo { public int Property { get; set; } } Bar bar = new Bar(); Foo foo = new Foo(); foo.Property = 10; bar.Foo = foo; bar.Foo.Property = 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it is not a variableAndrei Alexandrescu Wrote:can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
On Wed, Jul 29, 2009 at 10:11 AM, KennyTM~<kennytm gmail.com> wrote:Bill Baxter wrote:rOn Wed, Jul 29, 2009 at 9:23 AM, Jarrett Billingsley<jarrett.billingsley gmail.com> wrote:On Wed, Jul 29, 2009 at 10:44 AM, Ary Borenszweig<ary esperanto.org.ar> wrote:Andrei Alexandrescu wrote:Kagamin wrote:Andrei Alexandrescu Wrote:structs can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c =3D 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c =3D 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.itto what Walter proposed). --- public class Bar { =A0 public Foo Foo { get; set; } } public struct Foo { =A0 public int Property { get; set; } } Bar bar =3D new Bar(); Foo foo =3D new Foo(); foo.Property =3D 10; bar.Foo =3D foo; bar.Foo.Property =3D 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because =Similarly, taking the address should lead to an error. auto ptr =3D &a.b; // ok if b is a field auto ptr =3D &a.b; // bogus if b is a property returning a non-lvalue --bbProbably Walter means a.b.c =3D 3; =A0 =A0 =A0// b is a field works, while a.b.c =3D 3; =A0 =A0 =A0// b is a getter is a useless call. Nevertheless, if b() uses ref-return then it is meaningful.Yeh, I don't understand how any of this has anything to do with properties. =A0It's the same question if you ask what should =A0a.b().c =3D 5 =A0do. =A0It's the same issue whether you have properties or not, and needs a solution whether you have properties or not. --bbis not a variableBooom, exactly what I said about rvalues.
Jul 29 2009
On Wed, 29 Jul 2009 13:22:14 -0400, Bill Baxter <wbaxter gmail.com> wrote:Similarly, taking the address should lead to an error. auto ptr = &a.b; // ok if b is a field auto ptr = &a.b; // bogus if b is a property returning a non-lvalueImpossible with the current implementation -- &a.b is a delegate :) -Steve
Jul 29 2009
On Wed, Jul 29, 2009 at 10:26 AM, Steven Schveighoffer<schveiguy yahoo.com> wrote:On Wed, 29 Jul 2009 13:22:14 -0400, Bill Baxter <wbaxter gmail.com> wrote=:Good point. I suppose we can chalk that up as another problem with not having real properties. Though if you were expecting it to be an int* then you'll probably encounter a compiler sooner or later. Just might be far from where the actual problem is. --bbSimilarly, taking the address should lead to an error. auto ptr =3D &a.b; =A0// ok if b is a field auto ptr =3D &a.b; // bogus if b is a property returning a non-lvalueImpossible with the current implementation -- &a.b is a delegate :)
Jul 29 2009
On Wed, Jul 29, 2009 at 10:36 AM, Bill Baxter<wbaxter gmail.com> wrote:On Wed, Jul 29, 2009 at 10:26 AM, Steven Schveighoffer<schveiguy yahoo.com> wrote:e:On Wed, 29 Jul 2009 13:22:14 -0400, Bill Baxter <wbaxter gmail.com> wrot=[edit]Similarly, taking the address should lead to an error. auto ptr =3D &a.b; =A0// ok if b is a field auto ptr =3D &a.b; // bogus if b is a property returning a non-lvalueImpossible with the current implementation -- &a.b is a delegate :)Good point. =A0I suppose we can chalk that up as another problem with not having real properties. =A0Though if you were expecting it to be an int* then you'll probably encounter a compiler*error*sooner or later. =A0Just might be far from where the actual problem is.--bb
Jul 29 2009
On Wed, Jul 29, 2009 at 10:11 AM, KennyTM~<kennytm gmail.com> wrote:Bill Baxter wrote:rOn Wed, Jul 29, 2009 at 9:23 AM, Jarrett Billingsley<jarrett.billingsley gmail.com> wrote:On Wed, Jul 29, 2009 at 10:44 AM, Ary Borenszweig<ary esperanto.org.ar> wrote:Andrei Alexandrescu wrote:Kagamin wrote:Andrei Alexandrescu Wrote:structs can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c =3D 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c =3D 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.itto what Walter proposed). --- public class Bar { =A0 public Foo Foo { get; set; } } public struct Foo { =A0 public int Property { get; set; } } Bar bar =3D new Bar(); Foo foo =3D new Foo(); foo.Property =3D 10; bar.Foo =3D foo; bar.Foo.Property =3D 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because =a.b as a field effectively "returns" a ref, so a.b.c=3D3 is OK. a.b as a property does not, so may be an error. Similarly if a.b() returns a ref or pointer, a.b().c =3D 3 is OK. but if a.b() returns a tmp, it a.b().c =3D 3 may be an error. Not really any different. Seems like BCS, Steve, and Jarrett are all over this red herring, though. --bbProbably Walter means a.b.c =3D 3; =A0 =A0 =A0// b is a field works, while a.b.c =3D 3; =A0 =A0 =A0// b is a getter is a useless call. Nevertheless, if b() uses ref-return then it is meaningful.Yeh, I don't understand how any of this has anything to do with properties. =A0It's the same question if you ask what should =A0a.b().c =3D 5 =A0do. =A0It's the same issue whether you have properties or not, and needs a solution whether you have properties or not. --bbis not a variableBooom, exactly what I said about rvalues.
Jul 29 2009
Bill Baxter wrote:Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected. One great thing about properties is that they are mostly interchangeable with fields. The a.b.c = 3 problem works against that. Andrei
Jul 29 2009
Andrei Alexandrescu wrote:Bill Baxter wrote:No. Whenever you do Expression1 . Expression2 . Expression3 = Expression4. and Expression 2 is a struct type, and Expression 3 is not a static field of the struct, that should be an error.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 29 2009
Ary Borenszweig wrote:Andrei Alexandrescu wrote:I don't think D allows expressions to the right of ".". AndreiBill Baxter wrote:No. Whenever you do Expression1 . Expression2 . Expression3 = Expression4. and Expression 2 is a struct type, and Expression 3 is not a static field of the struct, that should be an error.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 29 2009
Andrei Alexandrescu wrote:Ary Borenszweig wrote:Ok, then change the rule to a . b . c = d; where b is an identifier or a function call, c is an identifier.Andrei Alexandrescu wrote:I don't think D allows expressions to the right of ".".Bill Baxter wrote:No. Whenever you do Expression1 . Expression2 . Expression3 = Expression4. and Expression 2 is a struct type, and Expression 3 is not a static field of the struct, that should be an error.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 29 2009
Ary Borenszweig wrote:Andrei Alexandrescu wrote:How about this fella then. a.b[5].c = d; Should work or not? AndreiAry Borenszweig wrote:Ok, then change the rule to a . b . c = d; where b is an identifier or a function call, c is an identifier.Andrei Alexandrescu wrote:I don't think D allows expressions to the right of ".".Bill Baxter wrote:No. Whenever you do Expression1 . Expression2 . Expression3 = Expression4. and Expression 2 is a struct type, and Expression 3 is not a static field of the struct, that should be an error.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 29 2009
Andrei Alexandrescu wrote:Ary Borenszweig wrote:Not if b[5] is a struct. Do I need to list evey possible syntax there it to get my point clear? :-( I'll change it to: a.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.Andrei Alexandrescu wrote:How about this fella then. a.b[5].c = d; Should work or not? AndreiAry Borenszweig wrote:Ok, then change the rule to a . b . c = d; where b is an identifier or a function call, c is an identifier.Andrei Alexandrescu wrote:I don't think D allows expressions to the right of ".".Bill Baxter wrote:No. Whenever you do Expression1 . Expression2 . Expression3 = Expression4. and Expression 2 is a struct type, and Expression 3 is not a static field of the struct, that should be an error.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 29 2009
On Wed, 29 Jul 2009 14:39:07 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:a.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.struct S { int *x; void c(int n) {*x = n;} } struct S2 { int n; S b() { return S(&n);} } void main() { S2 a; a.b.c = 5; } Why should this not be allowed?
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 14:39:07 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Because in the general case it might not work. It's simple: if you disallow it, no bugs caused because of this can exist. If you don't disallow it, sometimes it might work, sometimes it won't work. Which option do you prefer as a programmer?a.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.struct S { int *x; void c(int n) {*x = n;} } struct S2 { int n; S b() { return S(&n);} } void main() { S2 a; a.b.c = 5; } Why should this not be allowed?
Jul 29 2009
On Wed, 29 Jul 2009 14:50:42 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Steven Schveighoffer wrote:I prefer to have the power to create whatever I want without the compiler telling me incorrectly that it won't work. why allow any programming at all? The programmer might write incorrect code! -SteveOn Wed, 29 Jul 2009 14:39:07 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Because in the general case it might not work. It's simple: if you disallow it, no bugs caused because of this can exist. If you don't disallow it, sometimes it might work, sometimes it won't work. Which option do you prefer as a programmer?a.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.struct S { int *x; void c(int n) {*x = n;} } struct S2 { int n; S b() { return S(&n);} } void main() { S2 a; a.b.c = 5; } Why should this not be allowed?
Jul 29 2009
Steven Schveighoffer Wrote:On Wed, 29 Jul 2009 14:50:42 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:I reply using the web page because Thunderbird gives me a Bad Request error (very strange). The cases where you do: a.b.c = 3; where b is a struct are probably few, and most of the time they lead to incorrect result, such as the Widget and Rectangle examples, and many others. So I prefer the compiler to tell me "Look, b is a struct, please make sure you know what you are doing". And I can tell you, most of the time you'll say "Thanks, compiler, I didn't notice that!". If the compiler is wrong, you just do: auto x = a.b; b.c = 3; and that's it. No big deal.Steven Schveighoffer wrote:I prefer to have the power to create whatever I want without the compiler telling me incorrectly that it won't work. why allow any programming at all? The programmer might write incorrect code! -SteveOn Wed, 29 Jul 2009 14:39:07 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Because in the general case it might not work. It's simple: if you disallow it, no bugs caused because of this can exist. If you don't disallow it, sometimes it might work, sometimes it won't work. Which option do you prefer as a programmer?a.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.struct S { int *x; void c(int n) {*x = n;} } struct S2 { int n; S b() { return S(&n);} } void main() { S2 a; a.b.c = 5; } Why should this not be allowed?
Jul 29 2009
On Wed, 29 Jul 2009 15:00:42 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Steven Schveighoffer Wrote:I retracted my original message (just found out how to do that), because I wrote "...without the telling me..." instead of "...without the *compiler* telling me..." You probably tried to reply to my original message ;)On Wed, 29 Jul 2009 14:50:42 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:I reply using the web page because Thunderbird gives me a Bad Request error (very strange).Steven Schveighoffer wrote:I prefer to have the power to create whatever I want without the compiler telling me incorrectly that it won't work. why allow any programming at all? The programmer might write incorrect code! -SteveOn Wed, 29 Jul 2009 14:39:07 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Because in the general case it might not work. It's simple: if you disallow it, no bugs caused because of this can exist. If you don't disallow it, sometimes it might work, sometimes it won't work. Which option do you prefer as a programmer?a.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.struct S { int *x; void c(int n) {*x = n;} } struct S2 { int n; S b() { return S(&n);} } void main() { S2 a; a.b.c = 5; } Why should this not be allowed?The cases where you do: a.b.c = 3; where b is a struct are probably fewLet's not forget that structs are the vehicle to extend the type system. I want to make my own pointer type, it has to be a struct. You're going to predjudice the compiler against my wrapper types because I *might* do something that confuses people.and most of the time they lead to incorrect result, such as the Widget and Rectangle examples, and many others.In fact, this is the *only* example I've seen. It leads me to believe we need a better approach to widgets and rectangles more than a better approach to properties. Like maybe making Rectangles and PointsSo I prefer the compiler to tell me "Look, b is a struct, please make sure you know what you are doing". And I can tell you, most of the time you'll say "Thanks, compiler, I didn't notice that!". If the compiler is wrong, you just do: auto x = a.b; b.c = 3; and that's it. No big deal.It is a big deal. Ever used Vista? It has a similar conservative approach to security. It makes Vista unusable in my opinion. -Steve
Jul 29 2009
Steven Schveighoffer wrote:On Wed, 29 Jul 2009 14:39:07 -0400, Ary Borenszweig <ary esperanto.org.ar> wrote:Simpler yet: class C { int x; } struct B { C c; } struct A { C x; B b() { return B(x); } void main() { A a; a.x = new C; a.b.c = 42; // fine, modifies the C object } Andreia.b.c = d; If b is anything that has a struct type, and c is anything else, the statement must report an error.struct S { int *x; void c(int n) {*x = n;} } struct S2 { int n; S b() { return S(&n);} } void main() { S2 a; a.b.c = 5; } Why should this not be allowed?
Jul 29 2009
Ary Borenszweig wrote:Andrei Alexandrescu wrote:Yes, you actually need to. It was the point of my post. AndreiAry Borenszweig wrote:Not if b[5] is a struct. Do I need to list evey possible syntax there it to get my point clear? :-(Andrei Alexandrescu wrote:How about this fella then. a.b[5].c = d; Should work or not? AndreiAry Borenszweig wrote:Ok, then change the rule to a . b . c = d; where b is an identifier or a function call, c is an identifier.Andrei Alexandrescu wrote:I don't think D allows expressions to the right of ".".Bill Baxter wrote:No. Whenever you do Expression1 . Expression2 . Expression3 = Expression4. and Expression 2 is a struct type, and Expression 3 is not a static field of the struct, that should be an error.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 29 2009
Andrei Alexandrescu wrote:Ary Borenszweig wrote:Simple rule: rvalues cannot be modified (i.e. rvalues are implicitly const). No need to list all situations that generate rvalues. Or does that miss any cases? -- Rainer Deyke - rainerd eldwood.comNot if b[5] is a struct. Do I need to list evey possible syntax there it to get my point clear? :-(Yes, you actually need to. It was the point of my post.
Jul 29 2009
On Wed, Jul 29, 2009 at 10:50 AM, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:Bill Baxter wrote:tionYeh, I don't understand how any of this has anything to do with properties. =A0It's the same question if you ask what should =A0a.b().c =3D 5 =A0do. =A0It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c =3D 5 makes it clear that there's a func=call in the mix, so the field-like behavior is not necessarily to be expected. One great thing about properties is that they are mostly interchangeable with fields. The a.b.c =3D 3 problem works against that.Maybe you were expecting it to be possible to make properties completely indistinguishable from fields? But that can't really be when you can take the address of a field and not a property. The goal has to be removing as many differences in behavior as possible. On the point above, a.b.c =3D 5 is dicey whether b is obviously a function call or not, if what b returns is not an lvalue. If I think a.b() is returning a ref and it doesn't, then I want the compiler to tell me I'm doing something silly -- if it can determine so. Properties or no properties. --bb
Jul 29 2009
Bill Baxter wrote:On Wed, Jul 29, 2009 at 10:50 AM, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:Not quite. If they were completelty indistinguishable from fields, they'd be fields.Bill Baxter wrote:Maybe you were expecting it to be possible to make properties completely indistinguishable from fields?Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected. One great thing about properties is that they are mostly interchangeable with fields. The a.b.c = 3 problem works against that.But that can't really be when you can take the address of a field and not a property.Correct. Probably there are other issues as well.The goal has to be removing as many differences in behavior as possible.Yah, but that's a bit vague. The a.b.c=3 problem is that a code that looks the same with fields or properties does very different things, and useless under certain conditions.On the point above, a.b.c = 5 is dicey whether b is obviously a function call or not, if what b returns is not an lvalue. If I think a.b() is returning a ref and it doesn't, then I want the compiler to tell me I'm doing something silly -- if it can determine so. Properties or no properties.Yah. That is by the way a wart inherited from C++. It's one of the few places where you can reach the address of an rvalue: you call a function returning an rvalue and then you call a member function of the rvalue. Inside that member function, there's no knowledge that the object is an rvalue. I strongly disliked that behavior of C++, and I dislike it as strongly for D. However, there are cases in which it *does* make sense to call a member function against an rvalue. But those are few and far apart, so I'd like us to look into disallowing member function calls against structs in all situation. That would rid us of this problem and many others. Andrei
Jul 29 2009
Andrei Alexandrescu wrote:Bill Baxter wrote:correctly and nobody has problems with it. Can't D just copy the idea and that's it? *It works.* modifies the struct itself, then doing something like: bar.Foo.Method(); // Method does this.Property = 30; then when you do: int x = bar.Foo.Property; x won't have the value 30. So I think D should also forbid invoking methods on returned structs. You can always assign Foo to a temporary and work from it.On Wed, Jul 29, 2009 at 10:50 AM, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:Not quite. If they were completelty indistinguishable from fields, they'd be fields.Bill Baxter wrote:Maybe you were expecting it to be possible to make properties completely indistinguishable from fields?Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected. One great thing about properties is that they are mostly interchangeable with fields. The a.b.c = 3 problem works against that.But that can't really be when you can take the address of a field and not a property.Correct. Probably there are other issues as well.The goal has to be removing as many differences in behavior as possible.Yah, but that's a bit vague. The a.b.c=3 problem is that a code that looks the same with fields or properties does very different things, and useless under certain conditions.On the point above, a.b.c = 5 is dicey whether b is obviously a function call or not, if what b returns is not an lvalue. If I think a.b() is returning a ref and it doesn't, then I want the compiler to tell me I'm doing something silly -- if it can determine so. Properties or no properties.Yah. That is by the way a wart inherited from C++. It's one of the few places where you can reach the address of an rvalue: you call a function returning an rvalue and then you call a member function of the rvalue. Inside that member function, there's no knowledge that the object is an rvalue. I strongly disliked that behavior of C++, and I dislike it as strongly for D. However, there are cases in which it *does* make sense to call a member function against an rvalue. But those are few and far apart, so I'd like us to look into disallowing member function calls against structs in all situation. That would rid us of this problem and many others.
Jul 29 2009
Ary Borenszweig wrote:Andrei Alexandrescu wrote:What about something like "array.length++;"? It's a very similar problem, but not quite the same. Generalizes to all unary operators I think.Kagamin wrote:to what Walter proposed). --- public class Bar { public Foo Foo { get; set; } } public struct Foo { public int Property { get; set; } } Bar bar = new Bar(); Foo foo = new Foo(); foo.Property = 10; bar.Foo = foo; bar.Foo.Property = 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it is not a variableAndrei Alexandrescu Wrote:structs can't define properties. AndreiKagamin wrote:Andrei Alexandrescu Wrote:IMHO it's quite the contrary, a.b.c = 3 is a very simple and concrete problem that emphatically shows we haven't gotten properties up to snuff.The question is very simple: given that we're used with a specific semantics for a.b.c = 3, how can we address the fact that the semantics of this familiar operation is so different (and likely so useless) when properties replace fields?You're solving problems that never came to life. Well... only as syntetic examples.
Jul 29 2009
"Ary Borenszweig" <ary esperanto.org.ar> wrote in message news:h4pn90$3070$1 digitalmars.com...what Walter proposed). --- public class Bar { public Foo Foo { get; set; } } public struct Foo { public int Property { get; set; } } Bar bar = new Bar(); Foo foo = new Foo(); foo.Property = 10; bar.Foo = foo; bar.Foo.Property = 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it is not a variableThe whole point of properties is that, to the outside observer, they behave, as much as possible, like plain fields. Obviously this can't be done in all cases (like getting an int* from &myIntProp), but in this case: widget.sizeAsAStructField.width = 10; // Works widget.sizeAsAStructProp.width = 10; // Doesn't work
Jul 30 2009
Nick Sabalausky wrote:"Ary Borenszweig" <ary esperanto.org.ar> wrote in message news:h4pn90$3070$1 digitalmars.com...I don't understand your example. What's wrong with it? What doesn't work as you expect and what is your expected result? In the first case, if you modify sizeAsAStructField.width, it's ok and should compile, because you are modifying sizeAsAStructField itself, not public struct Foo { public int Property { get; set; } } public class Bar { public Foo Foo; } static Main() { Bar bar = new Bar(); Foo foo = new Foo(); foo.Property = 10; bar.Foo = foo; bar.Foo.Property = 20; // prints 20, as expected Console.WriteLine(bar.Foo.Property); }what Walter proposed). --- public class Bar { public Foo Foo { get; set; } } public struct Foo { public int Property { get; set; } } Bar bar = new Bar(); Foo foo = new Foo(); foo.Property = 10; bar.Foo = foo; bar.Foo.Property = 20; // line 16 --- Error on line 16: Cannot modify the return value of 'Bar.Foo' because it is not a variableThe whole point of properties is that, to the outside observer, they behave, as much as possible, like plain fields. Obviously this can't be done in all cases (like getting an int* from &myIntProp), but in this case: widget.sizeAsAStructField.width = 10; // Works widget.sizeAsAStructProp.width = 10; // Doesn't work
Jul 30 2009
"Ary Borenszweig" <ary esperanto.org.ar> wrote in message news:h4su5p$2ctj$1 digitalmars.com...Nick Sabalausky wrote:--------------------- public struct MyStruct { public int x; } public class ClassWithProp { // The whole point of properties is that the interface // for these two should work as similarly as possible. public MyStruct field; public MyStruct prop {get;set;} } static Main() { ClassWithProp classWithProp = new ClassWithProp(); // Works classWithProp.field.x = 10; // *But*, unlike "&field" vs "&prop", this prop-vs-field // inconsistency *is* easily fixable, // and therefore should be fixed. classWithProp.prop.x = 10; } ---------------------The whole point of properties is that, to the outside observer, they behave, as much as possible, like plain fields. Obviously this can't be done in all cases (like getting an int* from &myIntProp), but in this case: widget.sizeAsAStructField.width = 10; // Works widget.sizeAsAStructProp.width = 10; // Doesn't workI don't understand your example. What's wrong with it? What doesn't work as you expect and what is your expected result? In the first case, if you modify sizeAsAStructField.width, it's ok and should compile, because you are modifying sizeAsAStructField itself, not a
Jul 30 2009
On 2009-07-30 15:32:58 -0400, "Nick Sabalausky" <a a.a> said:The whole point of properties is that, to the outside observer, they behave, as much as possible, like plain fields. Obviously this can't be done in all cases (like getting an int* from &myIntProp), but in this case: widget.sizeAsAStructField.width = 10; // Works widget.sizeAsAStructProp.width = 10; // Doesn't workI'm undecided about what to do here. But I'd like to note that while common in our current examples, assignment to a member of the returned struct is *one* thing that can change the struct. Any function taking a non-const reference to the struct can also change it. For instance, let's add a call to a mutator for the size struct of your example: widget.sizeAsStructProp.increaseBy(10, 10); In this case, you'll also want the compiler automatically call the setter once it's done. And that doesn't apply only to member functions, you could define it a standalone function taking a ref to the struct and call it that way: increaseSizeBy(widget.size.sizeAsStructProp, 10, 10); In all those cases, you'll want to call the setter back once the struct has been modified. Don't take this as an argument for or against automatically setting the modified struct property value; I'm just pointing out that operators (and specially the assignment operator) isn't the only way to change a value. Assuming the non-mutator functions take a const ref to the struct, the compiler should be able to avoid setting back the property value when it's not necessary. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 30 2009
Walter Bright wrote:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property..... unless it returns a ref.
Jul 29 2009
On 2009-07-28 22:33:53 -0400, Walter Bright <newshound1 digitalmars.com> said:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions.With the local namespace approach I propsed a little while ago, you could allow "subproperties": namespace a { namespace b { namespace c { int opGet() {...} void opAssign(int) {...} } } } or (alternate syntax for the above): int a.b.c.opGet() {...} void a.b.c.opAssign(int) {...} Although it'd be somewhat clumbersome to redefine every member of a struct like this each time you make a property just so assigning to it works fine (I guess a mixin or some compiler magic could help).with this.Me neither.One thought I had was to simply disallow the '.' to appear after a function style property.I think that's a little harsh. If you return something by reference (like an object), the waterver you do to that object won't be lost. It's for value types (like structs) that this is a problem. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 29 2009
Michel Fortin wrote:On 2009-07-28 22:33:53 -0400, Walter Bright <newshound1 digitalmars.com> said:We're looking for a modular solution - one that allows one person to define the type of b and another person to define the type of a, which has a member b. AndreiThe issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions.With the local namespace approach I propsed a little while ago, you could allow "subproperties": namespace a { namespace b { namespace c { int opGet() {...} void opAssign(int) {...} } } }
Jul 29 2009
On Tue, 28 Jul 2009 22:33:53 -0400, Walter Bright <newshound1 digitalmars.com> wrote:The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3?There's one way you could do it -- since the return value is a temporary, it should not be an lvalue. But it's members could be lvalues, but only if they 1) are reference types or 2) implement opAssign. So for instance: struct S1 { int c; } If a.b returns an S, then it's not an lvalue, and since c is part of the struct, it's also not an lvalue, so the result should be an error. If a.b returns a ref S, then it's an lvalue, and c is also an lvalue. I think the compiler already restricts you from assigning to rvalues, so it could be extended. An opAssign example: struct S2 { private int *refdint; void opAssign(int x) {*refdint = x;} } if a.b.c returned an S2, even as a temporary, then it should be allowed. Unfortunately, even if the opAssign simply stores the result inside the S2 struct, then you still need to allow it, because the compiler cannot tell what the opAssign is going to do.It's a classic problem with properties that are implemented as functions.Is there another implementation that allows this to work magically? I've only ever seen properties as functions.with this.And I don't see why it should, or where anyone said it would. The syntax only helps to allow the author to explain what a property is. there is no issue.One thought I had was to simply disallow the '.' to appear after a function style property.Then you forbid struct types that wrap a reference from being returned, or from affecting ref types that were returned. -Steve
Jul 29 2009
Reply to Walter,The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. dealing with this. One thought I had was to simply disallow the '.' to appear after a function style property.seems related to this: http://d.puremagic.com/issues/show_bug.cgi?id=3008
Jul 29 2009
"Walter Bright" <newshound1 digitalmars.com> wrote in message news:h4ocet$27k$1 digitalmars.com...The issue is what if b is a property, returns a temporary object, and that temp's .c field is uselessly set to 3? It's a classic problem with properties that are implemented as functions. with this. One thought I had was to simply disallow the '.' to appear after a function style property.Disallow it by default. IE. a.b.c.d = 3; If any of those return an rvalue / temporary then it should be an error to assign to it. However we should not disallow... int i = a.b.c.d.e.f; But we should also find a way to let the programmer tell the compiler if it is ok for it to rewrite... a.b.c = 3; as B tmp = a.b; tmp.c = 3; a.b = tmp; perhaps an extra operator opSubAssign() Which tells the compiler it's ok to rewrite the the assignment using temporrarys and reassignment. class A { B _b; void b.opAssign(ref B bbb) { _b = bbb; } void b.opSubAssign(ref B bbb) { opAssign(bbb); } } Then the programmer could also write an specialized subassignment.
Jul 30 2009
Andrei Alexandrescu Wrote:Bill Baxter wrote:This is a matter of coding style I believe. widget.clientRectangle.width=10; widget.getRectangle(Rects.clientRectangle).width=10; Should the meaning of this code change depending on whether the return value is reference type or value type? supposed to be simply composite types rather than generic value types.Yeh, I don't understand how any of this has anything to do with properties. It's the same question if you ask what should a.b().c = 5 do. It's the same issue whether you have properties or not, and needs a solution whether you have properties or not.Well the problem is that a.b().c = 5 makes it clear that there's a function call in the mix, so the field-like behavior is not necessarily to be expected.
Jul 31 2009