DIP24
Contents
DIP24 Proposal: Fixing properties and optional parens.
Title: | Fixing properties and optional parens. Only those. In a general and straightforward way. |
---|---|
DIP: | 24 (counter proposal to DIP23) |
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 a lot of emphasis on special cases. This proposal attempts to give simple, general, comprehensive and implementable rules. The proposal is divided into three stages. The first stage is given by the next two subsections. It is also the most fleshed-out part. Its scope is about the same as DIP23's.
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.