DIP23 Counter Proposal

Timon Gehr timon.gehr at gmx.ch
Wed Feb 6 09:41:31 PST 2013


On 02/06/2013 04:32 PM, Andrei Alexandrescu wrote:
> On 2/5/13 7:39 PM, Timon Gehr wrote:
>> As my posts in the DIP23 thread have been left unanswered, I have
>> prepared a counter proposal for DIP23 during the last hour.
>>
>> Everything DIP23 addresses is specified in the two short sub-sections
>> "Optional parens" and "@property: basic design".
>>
>> Those in favour of what was called "semantic rewrites" in the DIP23
>> thread should probably read on further.
>>
>> All parts of this proposal are independent of DIP24 (which Andrei is
>> preparing).
>>
>> http://wiki.dlang.org/DIP23_Counter_Proposal
>>
>> There are almost no examples yet, but in case it is not clear how some
>> case would be handled, feel free to ask.
>
> So syntactic case (2) prescribes that when foo is in address-taken
> position "&foo", that means take its address as opposed to evaluate foo.
> That makes the use of "&" here sheer punctuation, as opposed to operator.
>

Here and everywhere else.

auto x = 5;
auto y = &5; // error!
auto z = &x; // ok!

> There's also "(Note that redundant parentheses are assumed to be dropped
> in the parsing stage.)" It's unclear whether this makes &(foo) and
> &(((foo))) identical to &foo. ...

That is exactly the case it describes. Yes it makes them identical.

> If they do, in this context parens are also
> punctuation, not expression grouping; they don't enclose an expression,
> but instead define &(((...(foo)...))) as a sole syntactic unit (!).
>

They are neither. They are just insignificant information thrown away by 
the parser.

> This also leads to potential confusion, seeing as &(foo) takes the
> address of foo, but &( true ? foo : bar ) does, in fact, take the
> address of whatever foo returns.

Ah, very good point! But please note that this is 100% a ternary 
operator issue.

Interestingly, what you describe is how it actually works in Scala. I do 
not feel strongly about this, but we might as well do it the other way.

I have clarified what it means to occur in a context. I think the 
ternary expression is the only composite expression that can occur in 
lvalue position that behaves this way.

This change also 'fixes' the related case (true ? foo : bar)().

> This makes the role of "&", "(", and
> ")" in the proposal as both punctuation and operator painfully visible.
>

The syntax tree looks like this:

       &
       |
       ?
     / | \
    /  |  \
true foo bar

There are no "(" ")". Why would they affect semantics?

> This all makes DIP24 fail meet its own definition of success as far as I
> understand it, i.e. keeping "&" to mean operator and parens to mean
> grouping.

1. There is no point where the DIP calls "&" an "operator".
2. It succeeds in keeping parens mean grouping. (Given any of the two 
behaviours of ternary expressions.)

DIP24 meets its own definition of success.

> In my opinion, it also makes DIP24 fail to improve over DIP23.
> ...

In my opinion too. It conveniently also makes all other statements true, 
as the line of reasoning crucially depends on fallaciously ascribing 
properties of the ternary operator to the parens enclosing it.

(The second fallacy is ascribing the properties of rvalue vs. lvalue 
distinction inherited from C to DIP24.)

> DIP23 has in fact /fewer/ such problems, because it clarifies that &foo
> and &expr.foo are indivisible syntactic units; thus parentheses are not
> ascribed a special meaning by DIP23.

That is inaccurate, and it is special enough that I do not care to fully 
formalize the special meaning ascribed to parentheses by DIP23.

Basically it makes use of parens affect whether some position in the 
syntax tree is treated as lvalue or rvalue position in some special cases.

> On the contrary, as soon as parens
> are used, as in &(foo) or &( true ? foo : bar ), the usual meaning
> of parens enters in action and give the expression inside the usual meaning.
>

You mean the usual rvalue position meaning, eliminating the lvalue 
position meaning, even if the expression actually occurs in an lvalue 
position. That is unusual.

> I should point out that that's all okay, but we got to be clear about
> it. Tokens are used as both punctuation and operators all the time. For
> example, it may sound weird that (stuff) and ((stuff)) should ever mean
> distinct things,

They never do and never should.

> but writeln((1, 2)) does something different from
> writeln(1, 2).

I guess this attempts to instantiate 'stuff' with "1, 2"?

The substring "((1, 2))" in the first example does not correspond to a 
node in the syntax tree. What is the point?

> This is because the outer layer is punctuation and the
> inner layer is expression grouping.

One of the usages is unary and the other is binary. Another example of 
this is ~x and x~y. This also shows that the two usages do not have to 
be related in any way, so nothing is weird.

> And nobody blinks an eye.

Of course they do. This situation is one cause of the extensive built-in 
tuple discussions.

> The language just needs to be as clear as possible about which is which.
>
> If DIP25 gets approved, taking the address of ref results will be
> banned, and therefore that potential meaning of "&" disappears, which
> simplifies things.

How? It only adds code to my front-end to make sure the case is actually 
caught and properly reported. It does not even simplify the byte code 
compiler. (Because it uses similar code paths for the &foo() and 
foo()=exp cases.)

> But we'll still have to live with the reality that in
> the constructs "&foo" and "&expr.foo", "&" is not an operator.

As well as in all other constructs where it is used in unary form.

> And that's okay.
>

Except for the unfortunate confusion it can cause.




More information about the Digitalmars-d mailing list