January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Monday, 28 January 2013 at 16:55:40 UTC, Dicebot wrote: > On Monday, 28 January 2013 at 16:50:37 UTC, Maxim Fomin wrote: >> Than value of this expression (note, that evaluated expression is not b, it is b = c) is assigned to a. > > Quoting you (that was exactly part of standard I was referring too): > "assignment expression has the value of the left operand" > > Left operand for (b = c) is b. Thus (b = c) has value of b. Value of b is b.getter(). Thus compiler is re-writing it wrong if we copy C rules. You are mixing value of expression and expression itself. If assignment expression has value of right operand, it does not mean that in complex assignment like a = b = c , right part of second assignment disappears and it becomes a = b. It is still a = b = c , and a is assigned to value of the whole expression b = c, not just value of b. This means it is a.setter((b = c)) = > a.setter(b.setter(c.getter)). Note, that original program does exactly what is required by ISO C. >> b.setter cannot be called prior to b.getter as in your example #1 due to sequence rules. The example #2 would be for expression a = c, b = c which is not a = b = c in the presence of properties. > > What sequence rules are you speaking about? About that side effects are sequenced after evaluation, but it is actually irrelevant, because b.getter is not called. |
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Monday, 28 January 2013 at 16:55:40 UTC, Dicebot wrote:
> On Monday, 28 January 2013 at 16:50:37 UTC, Maxim Fomin wrote:
>> Than value of this expression (note, that evaluated expression is not b, it is b = c) is assigned to a.
>
> Quoting you (that was exactly part of standard I was referring too):
> "assignment expression has the value of the left operand"
>
> Left operand for (b = c) is b. Thus (b = c) has value of b. Value of b is b.getter(). Thus compiler is re-writing it wrong if we copy C rules.
>
Applying your logic:
Left operand for a = (b = c) is a. Thus a has value of (b = c). Value of b = c is b.setter(c.getter()).
|
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | On Monday, 28 January 2013 at 17:20:13 UTC, Maxim Fomin wrote: > ... Those are C rules, do not forget it. Thus value of (b = c) IS equivalent to value of b when lvalues are considered. And you are perfectly allowed to forget about c and do a = b after b = c was evaluated. It is plain old data, after all, if b = c is not interchangeable with b, something is wrong. At least I see nothing in standard that proves your statement. > > Applying your logic: > > Left operand for a = (b = c) is a. Thus a has value of (b = c). Value of b = c is b.setter(c.getter()). You are applying it wrong. Thing of it as of recursion. 1) evaluate "a = b = c" 2) evaluate a.set( (b = c).get() ), result of 1 will be a.get() ( if needed ) 3) evaluate "b = c" 4) evaluate b.set( c.get() ), result of 3 will be b.get() ( if needed ) 5) combine: a.set( b.set( c.get() ), b.get() ) Note that evaluation order for comma expression is defined, so "c.get() ), b.get()" is valid and correct code. |
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Monday, 28 January 2013 at 03:24:09 UTC, Steven Schveighoffer wrote:
> There are three intentions when creating a function w/ regards to properties:
>
> 1. You intend the function to be called without parentheses to clarify it is a property.
> 2. You intend the function to be only called with parentheses to clarify it is a function.
> 3. You don't care whether it's called with parentheses or not, because the name of the function is clearly a property or a function.
This is a good point. Possibly since I'm the author of the following proposal, but also because I hope it will garner greater consideration than it has so far, this is how you would do these with my suggested language features single-instance structs and opGet:
The new syntax changes:
struct __foo {}
__foo foo;
to:
foo struct {}
This makes single-instance structs as easy to write as lambda functions. Combining them with two new operator definitions opGet and... let me see... opDo should cover it... it would look like this:
struct Goo
{
int _n;
foo struct
{
int opGet() { return _n; } // Exactly like opCall, but may not be used with parentheses
}
}
Goo g;
g.foo(); // Error
A struct may have exactly one of opGet, opCall, and opDo.
foo struct
{
int opGet() { ... }
int opDo() { ... } // Error: a struct may not have both opGet and opDo
}
opDo does exactly the opposite of opGet: it mandates the uses of parentheses instead of prohibits them. opCall, on the other hand, permits either one freely.
foo struct { int opDo() { return 4; } }
foo; // Error: foo must be called with parentheses
Note how the single-instance struct does not store data of its own, but is used for its value as a namespace and its ability to overload variables. That doesn't mean you *can't* store data in it. It's just like any other struct except that is has what I was thinking of calling a Highlander type: There can be only one!
|
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Monday, January 28, 2013 13:31:34 Jacob Carlborg wrote:
> > Having the compiler lower the following:
> >
> > @property int a;
> >
> > to
> >
> > private int __a;
> >
> > @property int a() {
> > return __a;
> > }
> > @property int a(int new_a) {
> >
> > __a=new_a;
> > return __a;
> >
> > }
>
> I would love that. But the setter should return void and the compiler should to property rewrites.
Both should work. It's more efficient to chain assignments if the setter returns a value, but chaining should still work if it returns void. It would just be lowered differently in that case.
- Jonathan M Davis
|
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Monday, 28 January 2013 at 17:41:07 UTC, Dicebot wrote: > On Monday, 28 January 2013 at 17:20:13 UTC, Maxim Fomin wrote: >> ... > > Those are C rules, do not forget it. Thus value of (b = c) IS equivalent to value of b when lvalues are considered. And you are perfectly allowed to forget about c and do a = b after b = c was evaluated. It is plain old data, after all, if b = c is not interchangeable with b, something is wrong. > > At least I see nothing in standard that proves your statement. > You are still breaking expression a = b = c and mixing terms of value of expression and expression itself. >> >> Applying your logic: >> >> Left operand for a = (b = c) is a. Thus a has value of (b = c). Value of b = c is b.setter(c.getter()). > > You are applying it wrong. Thing of it as of recursion. I applied exactly as you did. > 1) evaluate "a = b = c" > 2) evaluate a.set( (b = c).get() ), result of 1 will be a.get() ( if needed ) .get() is wrong here. Expression is a = b = c, not a = ( (b = c).get )) > 3) evaluate "b = c" > 4) evaluate b.set( c.get() ), result of 3 will be b.get() ( if needed ) > 5) combine: a.set( b.set( c.get() ), b.get() ) This breaks requirement from quoted paragraph that side effects are sequenced after value computations on both operands: computing value of b (b.get) happened after updating value (b.set). In Bugzilla there were close to this case like following (do not remember #): struct S { int a; int b; int c; } ... S s1, s2; s1 = { 1, s1.a 2 } Compiler was wrongly applied side effects before evaluating s1.a (it should be zero, not 1). > Note that evaluation order for comma expression is defined, so "c.get() ), b.get()" is valid and correct code. Well, discussion went repetitive - I still insists that a = b = c should be evaluated as it is currently a.set(b=c) = > a.set(b.set(c)) => a.set(b.set(c.get)). By the way, this C# program also behaves as I understand rules: using System; using System.Collections.Generic; using System.Linq; using System.Text; class S { int _i; public int i { get { Console.WriteLine("getter"); return _i; } set { Console.WriteLine("setter"); _i = value; } } } namespace ConsoleApplication1 { class Program { static void Main(string[] args) { S s1 = new S() , s2 = new S(), s3 = new S(); s1.i = s2.i = s3.i; } } } getter setter setter |
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | On 2013-01-28 15:00, Maxim Fomin wrote: > Returning void instead of int in the example break assignment chaining a > = b = c. Besides, how such implicitly defined functions may call user > defined code (check input validity, call events, etc.)? No, the compiler should do a rewrite, as follows: class Foo { int bar_; @property int bar () { return bar_; } @property void bar (int value) { bar_ = value; } } auto foo = new Foo; int a = foo.bar = 3; The above line should be rewritten as: foo.bar = 3; int a = foo.bar; The compiler also need to rewrite the following: struct Bar { int a; } class Foo { Bar bar_; @property Bar bar () { return bar_; } @property void bar (Bar value) { bar_ = value; } } auto foo = new Foo; foo.bar.a = 3; The above line should be rewritten to: auto __tmp = foo.bar; __tmp.a = 3; foo.bar = __tmp; If not, the value of "foo.bar.a" hasn't really changed since you returned a copy by value. If you instead return by reference you can bypass the setter using the getter. -- /Jacob Carlborg |
January 28, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 2013-01-28 17:21, Steven Schveighoffer wrote: > I think Jacob's point is that a = b = c would lower to: > > b = c; > a = b; This is how the semantics should be. This also shows a clear complete example: http://forum.dlang.org/thread/uxhgbxdsselokcdkvltx@forum.dlang.org?page=14#post-ke6l44:242mfh:241:40digitalmars.com > But I think it would be wasteful in the given case. __a is already in > the register, I think actually the return __a is a noop. > > In other cases, where the property value may be a large struct or > whatnot, not returning the new value from a setter would make sense. > > It would be nice if the compiler made the right choice depending on > whether you returned a value from the property or not. Then it's up to the compiler to implement them, I don't need to know the details in the optimizations it can do. -- /Jacob Carlborg |
January 29, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Mon, 28 Jan 2013 15:00:41 -0500, Jacob Carlborg <doob@me.com> wrote: > On 2013-01-28 17:21, Steven Schveighoffer wrote: >> But I think it would be wasteful in the given case. __a is already in >> the register, I think actually the return __a is a noop. >> >> In other cases, where the property value may be a large struct or >> whatnot, not returning the new value from a setter would make sense. >> >> It would be nice if the compiler made the right choice depending on >> whether you returned a value from the property or not. > > Then it's up to the compiler to implement them, I don't need to know the details in the optimizations it can do. Like I said, the synthesizing of properties can be done via a library. The compiler simply needs to call the getter when the setter returns void, or return the setter's return value when it returns a value. -Steve |
January 29, 2013 Re: @property needed or not needed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Mon, 28 Jan 2013 15:00:41 -0500, Jacob Carlborg <doob@me.com> wrote: > On 2013-01-28 17:21, Steven Schveighoffer wrote: >> But I think it would be wasteful in the given case. __a is already in >> the register, I think actually the return __a is a noop. >> >> In other cases, where the property value may be a large struct or >> whatnot, not returning the new value from a setter would make sense. >> >> It would be nice if the compiler made the right choice depending on >> whether you returned a value from the property or not. > > Then it's up to the compiler to implement them, I don't need to know the details in the optimizations it can do. Like I said, the synthesizing of properties can be done via a library. The compiler simply needs to call the getter when the setter returns void, or return the setter's return value when it returns a value. -Steve |
Copyright © 1999-2021 by the D Language Foundation