DIP23 Counter Proposal

From D Wiki
Revision as of 01:24, 6 February 2013 by Tgehr (talk | contribs) (@property: basic design)
Jump to: navigation, search

DIP23 Counter Proposal: Fixing properties and optional parens.

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 optional implicit this pointer)

In the first cases, the function is a @property getter. In the second cases, it is a @property setter.

(For templated functions, this restriction is checked after template instantiation as is usual.)

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.