February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 02/03/2013 03:16 AM, Andrei Alexandrescu wrote:
> Walter and I have had a discussion on how to finalize properties.
>
> http://wiki.dlang.org/DIP23
>
> We got input from DIP21 (which we didn't want to clobber, hence the new
> DIP) and the recent discussion.
>
> The proposal probably won't be accepted in its current form because it
> breaks some code. We hope to bring it to good shape with everyone's help.
>
> In brief:
>
> * Optional parens stay.
>
> * Just mentioning a function or method without parens does NOT
> automatically take its address. (This is a change from the current
> behavior.)
>
> * Read properties (using @property) work as expected with the mention
> that they may NOT be called with the parens. Any parens would apply to
> the returned value.
>
> * Write properties (using @property) may only be used in the assignment
> form (no function-style call allowed).
>
> It is understood that the current proposal is just a draft and there
> must be quite a few corner cases it doesn't discuss. We also understand
> it's impossible to reconcile all viewpoints and please all tastes. Our
> hope is to get to a point where the rules are self-consistent,
> meaningful, and complete.
>
>
> Destroy.
>
> Andrei
This would be a huge step up from the current properties. Thank you for listening and being rigorous.
------
There are a couple things in the DIP that I might be able to destroy; here's the first:
the property rewrite is chosen based on whether it compiles or not.
I don't like the rule and its potential ambiguities. When I was attempting a property rewrite patch for DMD, one of the first things I did was match the different contexts a property expression may appear in:
- read-only
- read-write
- write-only
In read-only contexts, stuff like "q = prop;" or "auto foo(T)(T x); ... foo(prop);" should only call the getter.
In read-write context, the full rewrite is applied. "prop++" expands to "(auto t = prop, t++, prop = t);". This could include things like appearing as the argument to a function's ref parameter, but I've been convinced at one point that it might be wiser to disallow that (unfortunately, I forget /why/).
In write-only contexts, only the setter is applied. This is stuff like "prop = q;" or "auto foo(T)(out T x); ... foo(prop);".
------
I would suggest guaranteeing that the property rewrite will evaluate the getter/setter no more than once in an expression.
------
As Jonathan M Davis pointed out, it should be possible to mark fields as @property and forbid address-of on such members.
------
I also think that allowing address-of on properties is dubious. I've mentioned that in another response.
There is no easy way to make address-of do the same thing for variables and for properties, so to make properties work consistently in the transition between POD to calculated data, it is easiest to just forbid address-of.
I think that allowing getters to return lvalues is dangerous in general. It could create ambiguities in the writer's intentions with getter/setter pairs: did they want prop++ to expand to (prop++) or (auto t = prop, t++, t = prop)? I think the latter should always be chosen, and the whole example should never compile if they only provide a getter.
|
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote: > ... > Couldn't AddressOf use "&(" + exp + ")"? > > I thought more about this. The problem remains even without @property, > due to optional parens in function invocation. Consider: > > ref int fun() { ... } > auto p1 = &fun; > auto p2 = &(fun); > auto p3 = &(fun()); > > What are the types of the three? The optional parens in invocation > require some disambiguation. The obvious rule is not to give significance to redundant parentheses. > I think the sensible disambiguation is to > have &fun take the address of fun and the other two take the address of > fun's result. > No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.) The rules are straightforward: A non-@property function name 'foo' denotes a function invocation without arguments iff it does not occur in one of the following contexts: 1. foo(...) // explicitly called 2. &foo // address taken 3. ...!(...,foo,...) // template argument (well, that's what DMD currently does) 4. alias ... = foo; // aliased > I would agree restricting the properties, but requiring a __trait to > take the address of a regular function or method seems overkill. > I have no idea how the conclusion would be reached that this is necessary under any of the discussed schemes. |
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 02/04/2013 04:13 AM, Andrei Alexandrescu wrote: > On 2/3/13 9:58 PM, David Nadlinger wrote: >> My point is precisely that. I think there are much simpler solutions >> than adding some magic properties to a pair of parentheses in the right >> position, even if it might look like a convenient hack. > > I don't think it's a hack at all. It is a horrible hack. Why is this not obvious? > Think it over, and compare it with the language semantics even today. > I am intimately familiar with today's language semantics as I am writing a D compiler front end. Please be more explicit. |
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> > > Couldn't AddressOf use "&(" + exp + ")"? > Yes. It's enough. I wanted to explain that "we should treat address-expression carefully". > I thought more about this. The problem remains even without @property, due to optional parens in function invocation. Consider: > > ref int fun() { ... } > auto p1 = &fun; > auto p2 = &(fun); > auto p3 = &(fun()); > > What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result. > Agreed. > I would agree restricting the properties, but requiring a __trait to take the address of a regular function or method seems overkill. Fully agreed. Although it looks strange and unstable, adding new distinction of semantics between &foo and &(foo) has no ambiguity. I think this is necessary feature for the D's function and property semantics. Kenji Hara |
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: > I'm unclear that's a problem. The problem is you cannot replace a field with a @property function without breaking user-code when you take into account operator overloading. Consider: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { S s; } void main() { M m; auto s = m.s & m.s; // ok } Suppose you want to turn 's' into a read-only property, so you write: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { @property S s() { return _s; } private S _s; } void main() { M m; auto s = m.s & m.s; // fail } Now the user-code fails. I really don't understand the benefit of semantics based on whether there are parens involved. It's especially odd when we're arguing that functions can be called with or without parens (no semantic difference), yet getting an address depends on any parens involved. Requiring an address of a property function should be rare, therefore we shouldn't have to introduce special syntax rules for such a rare action. I'd argue we should introduce a trait or an .addrOf property. |
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to kenji hara | On 02/04/2013 03:38 PM, kenji hara wrote: > 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org > <mailto:SeeWebsiteForEmail@erdani.org>> > > > Couldn't AddressOf use "&(" + exp + ")"? > > > Yes. It's enough. I wanted to explain that "we should treat > address-expression carefully". > > I thought more about this. The problem remains even without > @property, due to optional parens in function invocation. Consider: > > ref int fun() { ... } > auto p1 = &fun; > auto p2 = &(fun); > auto p3 = &(fun()); > > What are the types of the three? The optional parens in invocation > require some disambiguation. I think the sensible disambiguation is > to have &fun take the address of fun and the other two take the > address of fun's result. > > > Agreed. > Why? > I would agree restricting the properties, but requiring a __trait to > take the address of a regular function or method seems overkill. > > > Fully agreed. > It is not an interesting point. It is not necessary anyway. > Although it looks strange and unstable, adding new distinction of > semantics between &foo and &(foo) has no ambiguity. > It _is_ strange. > I think this is necessary feature for the D's function and property > semantics. > Why? |
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Attachments:
| 2013/2/4 Andrej Mitrovic <andrej.mitrovich@gmail.com> > On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: > > I'm unclear that's a problem. > > The problem is you cannot replace a field with a @property function without breaking user-code when you take into account operator overloading. Consider: > As an essential question, how often occurs rewriting fields to property? As far as I thought, such rewriting will cause: 1. compile error by type mismatch (if you use &obj.field), 2. or, success of compilation *without any semantic breaking* (if you don't use &obj.field). I think the result is not so harmful. > struct S > { > S opBinary(string op : "&", S)(S s) > { > return this; > } > } > > struct M > { > S s; > } > > void main() > { > M m; > auto s = m.s & m.s; // ok > } > > Suppose you want to turn 's' into a read-only property, so you write: > > struct S > { > S opBinary(string op : "&", S)(S s) > { > return this; > } > } > > struct M > { > @property S s() { return _s; } > private S _s; > } > > void main() > { > M m; > auto s = m.s & m.s; // fail > } > > Now the user-code fails. > This is not correct."m.s & m.s" is always parsed as binary bitwise AND expression. So there is no address expression. Kenji Hara |
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On Monday, 4 February 2013 at 14:25:10 UTC, Timon Gehr wrote:
> On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:
>> ...
>> Couldn't AddressOf use "&(" + exp + ")"?
>>
>> I thought more about this. The problem remains even without @property,
>> due to optional parens in function invocation. Consider:
>>
>> ref int fun() { ... }
>> auto p1 = &fun;
>> auto p2 = &(fun);
>> auto p3 = &(fun());
>>
>> What are the types of the three? The optional parens in invocation
>> require some disambiguation.
>
> The obvious rule is not to give significance to redundant parentheses.
>
>> I think the sensible disambiguation is to
>> have &fun take the address of fun and the other two take the address of
>> fun's result.
>>
>
> No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.)
>
Scala don't really agree. fun is the function pointer. It is evaluated if the function pointer is a NOOP, but that's it. Here is scala semantic with D syntax :
void bar() {}
bar; // execute bar. Is an exception because taking the function pointer is a NOOP.
void foo(void function() bar) {}
foo(bar); // OK, bar is not evaluated.
|
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr Attachments:
| 2013/2/4 Timon Gehr <timon.gehr@gmx.ch>
> On 02/04/2013 03:38 PM, kenji hara wrote:
>
>> I think this is necessary feature for the D's function and property semantics.
>>
>
> Why?
>
Because, "property" is one of D-specific feature.
In D, "property" is directly translated to function call. So, we should get
balance between two requirements:
1. property should be treated as its returned type.
2. property should be distinguished from raw field. (For example,
serialization library should recognize it)
Address expression is _only_one_ built-in feature to make a callable object
from function symbol. So
this "special feature" is enough reasonable to me.
Kenji Hara
|
February 04, 2013 Re: DIP23 draft: Fixing properties redux | ||||
---|---|---|---|---|
| ||||
On 2/4/13, kenji hara <k.hara.pg@gmail.com> wrote: > This is not correct."m.s & m.s" is always parsed as binary bitwise AND expression. So there is no address expression. Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operator On 2/4/13, kenji hara <k.hara.pg@gmail.com> wrote: > Address expression is _only_one_ built-in feature to make a callable object > from function symbol. So > this "special feature" is enough reasonable to me. Yes "only one". And then later we'll add another "one", and another one, until we end up with the mess that is C++. This feature does not pull its own weight regardless of how easy it is to implement in the compiler. From a user's perspective, it is completely pointless and unintuitive. |
Copyright © 1999-2021 by the D Language Foundation