|
|
Line 1: |
Line 1: |
− | == DIP23 Counter Proposal: Fixing properties and optional parens. ==
| |
− | {| class="wikitable"
| |
− | !Title:
| |
− | !'''Fixing properties and optional parens. Only those. In a general and straightforward way.'''
| |
− | |-
| |
− | |DIP:
| |
− | |23 (counter proposal)
| |
− | |-
| |
− | |Version:
| |
− | |1
| |
− | |-
| |
− | |Status:
| |
− | |Draft
| |
− | |-
| |
− | |Created:
| |
− | |2013-02-06
| |
− | |-
| |
− | |Last Modified:
| |
− | |2013-02-06
| |
− | |-
| |
− | |Author:
| |
− | |Timon Gehr
| |
− | |-
| |
− | |Links:
| |
− | |
| |
− | |}
| |
| | | |
− | == Motivation ==
| |
− |
| |
− | The DIP23 draft does not address all requests and only deals with a subset of cases. Furthermore, it is specified by example and has too much emphasis on special cases instead of general and implementable rules.
| |
− |
| |
− | == Optional parens ==
| |
− |
| |
− | A symbol 'foo' that refers to a non-@property-qualified function or function template is rewritten to foo() iff it does not occur in one of the following contexts:
| |
− |
| |
− | 1. Function call position ( foo(args) )
| |
− | 2. Address-taken position ( &foo )
| |
− | 3. Instantiation position ( foo!args )
| |
− | 4. Template argument position ( tmpl!(args1, foo, args2) )
| |
− |
| |
− | (Note that redundant parentheses are assumed to be dropped in the parsing stage.)
| |
− |
| |
− | == @property: basic design ==
| |
− |
| |
− | A global @property function may have one or two arguments. (those are intended to be used UFCS-style only)
| |
− | A member @property function (static or instance) may have zero or one argument. (additionally to the implicit this pointer, if there is any)
| |
− |
| |
− | (For templated functions, this restriction is checked after template instantiation.)
| |
− |
| |
− | In the first cases, the function is a @property getter. In the second cases, it is a @property setter.
| |
− |
| |
− | It is illegal to overload @property-qualified functions against non-@property-qualified functions.
| |
− |
| |
− | The following rewrite is assumed to be always applied on the entire AST WLOG: (this gets rid of an annoying border case)
| |
− | (exprs, b) (op)= exp is rewritten to (exprs, b (op)= exp)
| |
− |
| |
− | The UFCS case is not discussed in detail, but it is straightforward.
| |
− |
| |
− | The following __traits is introduced:
| |
− | __traits(propertyAccessors, propertySymbol)
| |
− |
| |
− | This expression behaves like the propertySymbol, except that it is not subject to any of the rewrite rules below.
| |
− |
| |
− | A symbol 'prop' that refers to a @property-qualified function or function template is rewritten to __traits(propertyAccessors, prop)() iff it does not occur in one of the following contexts:
| |
− |
| |
− | 1. Assignment position: prop = exp
| |
− | -- In this case, there are two possibilities:
| |
− | -- - typeof(__traits(propertyAccessors, prop)(exp)) is void => The whole expression is rewritten to (__traits(propertyAccessors, prop)(exp), prop)
| |
− | -- - otherwise, the whole expression is rewritten to __traits(propertyAccessors, prop)(exp)
| |
− |
| |
− | == @property: possible extensions ==
| |
− |
| |
− | Everything below should be appended to the proposal if the consensus is to support simple "semantic rewrites":
| |
− | --------------------------------------------------------------------------------------------------------------
| |
− |
| |
− | 2. OpAssign position: prop op= exp
| |
− | -- In this case, the whole expression is rewritten to {auto val=prop; val op= exp; return prop=val; }(), where 'val' is choosen such that it does not occur free in exp or prop.
| |
− |
| |
− | 3. Prefix increment/decrement position: ++prop or --prop
| |
− | -- In this case, the whole expression is rewritten to prop+=1 or prop-=1 respectively.
| |
− |
| |
− | 4. Suffix increment/decrement position: prop++ and prop--
| |
− | -- In this case, the usual rewrites for prop++ and prop-- are applied before prop is rewritten.
| |
− |
| |
− | Everything below should be appended to the proposal if the consensus is to support full "semantic rewrites":
| |
− | ------------------------------------------------------------------------------------------------------------
| |
− |
| |
− | The following cases only apply if typeof(prop) can be successfully evaluated to a value type. i.e. a type that is not a class reference, pointer, slice, function pointer, or delegate.
| |
− |
| |
− | 5. IndexAssign and OpIndexOpAssign: prop[indexes] (op)= exp
| |
− | -- In this case, the whole expression is rewritten to {auto val=prop; val[indexes] (op)= exp; return prop=val; }(), where 'val' is choosen such that it does not occur free in exp or prop.
| |
− |
| |
− | 6. Field access position: (context) prop.ident (context), if the context corresponds to any one context from 1 to 6, but not only 6
| |
− | -- In this case, the expression is rewritten to {auto val1=prop, val2=(context) val1.ident (context); prop=val1; return val2 }(), where 'val1'/'val2' are choosen such that they does not occur free in exp or prop or in each other.
| |
− | (This last rule is formulated in a somewhat informal way and could be stated more rigorously if the need arises.)
| |
− |
| |
− | == Applicability of "semantic rewrites" to operator overloading ==
| |
− |
| |
− | The "semantic rewrite" strategy would probably need to be employed for operator overloading as well:
| |
− |
| |
− | S s; // s is a struct, s.x is a field
| |
− | ++s[i].x;
| |
− |
| |
− | the last expression would be rewritten according to almost identical rules to
| |
− |
| |
− | {auto val1=s[i], val2=++val1.x; s[i]=val1; return val2; }()
| |
− |
| |
− | == A note on implementation ==
| |
− |
| |
− | The compiler is of course free to use more efficient strategies that lead to the same semantics.
| |
− | Error messages should ideally not expose the rewritten code.
| |