Difference between revisions of "DIP24"

From D Wiki
Jump to: navigation, search
(Optional parens)
m (@property: possible extensions)
Line 83: Line 83:
 
--------------------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------------------
  
   2. OpAssign position: prop op= exp
+
   4. 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.
 
   -- 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
+
   5. Prefix increment/decrement position: ++prop or --prop
 
   -- In this case, the whole expression is rewritten to prop+=1 or prop-=1 respectively.
 
   -- In this case, the whole expression is rewritten to prop+=1 or prop-=1 respectively.
  
   4. Suffix increment/decrement position: prop++ and prop--
+
   6. Suffix increment/decrement position: prop++ and prop--
 
   -- In this case, the usual rewrites for prop++ and prop-- are applied before prop is rewritten.
 
   -- In this case, the usual rewrites for prop++ and prop-- are applied before prop is rewritten.
  
Line 97: Line 97:
 
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.
 
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
+
   7. 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.
 
   -- 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
+
   8. 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.
 
   -- 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.)
 
(This last rule is formulated in a somewhat informal way and could be stated more rigorously if the need arises.)

Revision as of 03:01, 6 February 2013

DIP24 Proposal: Fixing properties and optional parens.

Title: Fixing properties and optional parens in a 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.

The other two stages specify the "semantic rewrite" feature that was requested a few times on the newsgroup to different extents. They are mostly independent of the first stage and can therefore be approved or rejected independently of the first stage.

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) )
 5. Aliased symbol position (alias sym = foo;,  alias foo sym;)

(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)
 2. Aliased symbol position (alias sym = prop;,  alias prop sym;)
 -- In this case, no rewrite takes place.
 3. Template alias argument position.
 -- In this case, the @property rewrite is reverted after it becomes clear that the argument is passed by alias.

@property: possible extensions

Everything below should be appended to the proposal if the consensus is to support simple "semantic rewrites":


 4. 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.
 5. Prefix increment/decrement position: ++prop or --prop
 -- In this case, the whole expression is rewritten to prop+=1 or prop-=1 respectively.
 6. 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.

 7. 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.
 8. 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.