www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [grammar] ambiguity on parenthized clauses

reply Manfred Nowak <svv1999 hotmail.com> writes:
The `debug' and `synchronized' statements both have the options to 
be followed immediately by a statement
  `synchronized stmt'
or have a parenthesed item between the keyword and the statement
  `synchronized( expr ) stmt'.

Because a statement can derive to an expression statement 
consisting of an expression that starts with a left parenthesis 
  `(*(new int))* *y;'
there is an ambiguity introduced if such a statement is turned into 
a `synchronized' statement
  `synchronized (*(new int))* *y;'

In fact the current dmd resolves this ambiguity in favor of
  `synchronized( expr ) stmt'
by implementing the rules
  `synchronized stmtThatDoesNotStartWithLeftParenthesis'
  `synchronized ( expr ) stmt'

So there are at least three choices:

1. Holding up the status quo, which means that some statements are 
not synchronizable
2. Requiring an empty pair of parenthesis between the keyword and 
the statement
   `synchronized ( ) stmt'
   `synchronized ( expr ) stmt'
3. Changing the parentheses to something else
   `synchronized stmt'
   `synchronized !( expr ) stmt'

Similar arguments hold for the debug statement.

-manfred
Apr 28 2005
next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:d4qdg2$eij$1 digitaldaemon.com...
 The `debug' and `synchronized' statements both have the options to
 be followed immediately by a statement
   `synchronized stmt'
 or have a parenthesed item between the keyword and the statement
   `synchronized( expr ) stmt'.

 Because a statement can derive to an expression statement
 consisting of an expression that starts with a left parenthesis
   `(*(new int))* *y;'
 there is an ambiguity introduced if such a statement is turned into
 a `synchronized' statement
   `synchronized (*(new int))* *y;'

 In fact the current dmd resolves this ambiguity in favor of
   `synchronized( expr ) stmt'
 by implementing the rules
   `synchronized stmtThatDoesNotStartWithLeftParenthesis'
   `synchronized ( expr ) stmt'

 So there are at least three choices:

 1. Holding up the status quo, which means that some statements are
 not synchronizable
I agree it is ambiguous, but statements that start with ( are generally contrived as the () are redundant. The example you gave can also be written as: *(new int) * *y; with no change in meaning. So option (1) works.
Apr 28 2005
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
"Walter" <newshound digitalmars.com> wrote:

[...]
 statements that start with ( are generally contrived as the ()
 are redundant.
May I remind on the fact that the evaluation order of expressions in general is not specified. Therefore one might very well be forced to introduce parentheses. And I do not think, that in `( a + b) * c' the parentheses are truly redundandent.
 The example you gave can also be written as:
     *(new int) * *y;
 with no change in meaning. So option (1) works.
Agreed, if there are no overloads. One can always rewrite the statement by turning it into a blockstatement. However, the drawnback of option (1) is, that forgetting the need to rewrite may introduce subtle errors. Again the probability is extremely low because the contents of the clauses must meet semantic constraints. However, is this suitable for a language which' design goal is to shield the programmer from unnecessary bugs? -manfred
Apr 28 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:d4rfg7$1lme$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote:
 statements that start with ( are generally contrived as the ()
 are redundant.
May I remind on the fact that the evaluation order of expressions in general is not specified. Therefore one might very well be forced to introduce parentheses. And I do not think, that in `( a + b) * c' the parentheses are truly redundandent.
Correct, they aren't redundant in that case, but the expression also has no effect and so one would not see: debug (a + b) * c; Furthermore, the argument to debug must be either an identifier or an integer literal. Anything else will give a syntax error. The argument to synchronize must resolve to an object reference. Add these up, and the chances are remote that there'd be any confusion not caught at compile time.
Apr 28 2005
parent Manfred Nowak <svv1999 hotmail.com> writes:
"Walter" <newshound digitalmars.com> wrote:

[...]
 Correct, they aren't redundant in that case, but the expression
 also has no effect and so one would not see:
 
     debug (a + b) * c;
ICNR. <code> import std.stdio; class Int{ Int opAdd(Int p){ writef("Paradise"); return new Int; } void opAdd(Object* P){ writefln("Forget what I just wrote!"); } Object* opMul(Object* p){ writefln(" turned into hell. Red alert!"); return null;} } void main(){ Int x=new Int,y=new Int; Object o; Object* z= &o; synchronized (x + y) * z; } </code> [...]
 Add these up, and the chances are remote that there'd be any
 confusion not caught at compile time. 
Agreed. But it really took not much time to construct the example above. -manfred
Apr 29 2005
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Manfred Nowak wrote:
<snip>
 1. Holding up the status quo, which means that some statements are 
 not synchronizable
<snip> What is there to stop you from doing synchronized { (*(new int))* *y; } ? Besides that this code would be a complete nop? Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Apr 29 2005
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Stewart Gordon <smjg_1998 yahoo.com> wrote:

 What is there to stop you from doing
 
      synchronized { (*(new int))* *y; }
 
 ?  Besides that this code would be a complete nop?
Thanks for the confirmation of my posting http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/3836 where I already mentioned the possibility to wrap each statement by a blockstatement. However, have a look at our own docs: <cite href="http://www.digitalmars.com/d/expression.html#NewExpression"> There is an ambiguity in the grammar, however. Consider: (foo) - p; Is this a cast of a dereference of negated p to type foo, or is it p being subtracted from foo? </cite> Do you agree that the fact that there _is_ an ambiguity can serve as an argument against a language? And both of your arguments hold here too: 1. The statement _can_ be rewritten as (foo / 1) - p to make clear that a cast is not wanted. 2. This staement in C is doubtless a NOOP in both possible interpretations. However in D this might be an OP because the operators are overloadable and therefore may have side effects. Can you prove, that this argument does not hold?
Apr 29 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Manfred Nowak wrote:
<snip>
 However, have a look at our own docs:
 
 <cite 
 href="http://www.digitalmars.com/d/expression.html#NewExpression">
 
 There is an ambiguity in the grammar, however. Consider: 
 		(foo) - p;
 	
 Is this a cast of a dereference of negated p to type foo, or is it 
 p being subtracted from foo?
 </cite>
If you had bothered to read what you just quoted, you would've noticed that it's talking about C(++) there. And that this isn't part of the NewExpression section.
 Do you agree that the fact that there _is_ an ambiguity can serve 
 as an argument against a language?
 
 And both of your arguments hold here too:
 1. The statement _can_ be rewritten as 
            (foo / 1) - p
 to make clear that a cast is not wanted.
<snip> This has been completely unnecessary since DMD 0.119. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
May 03 2005
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Stewart Gordon <smjg_1998 yahoo.com> wrote:

[...]
 If you had bothered to read
[...] Hey, Stewart. We are now getting into troubles because the limitations of this medium! I know very well, that the example referenced is talking on C(++). All I wanted to say is, that Walter himself uses the pure existence of an ambiguity in C(++) as an argument against C(++). So, if he is not too self contained, after the above he also _must_ use the pure existence of an ambiguity in D as an argument against D. Once more: all I want to express is that by prepending the synchronized keyword before a statement nobody would expect that the semantic of that statement may change. That is the same thing as with the preepnding of a cast: a cast is also not expected to change the semantic value of the expression casted. So if D prevents the programmer from unforseeable bugs by introducing a syntactical element for casts, the kywaord `cast', to eliminate this ambiguity, it is reasonable to prevent every programmer from this ambiguity introduced by the specs of D itself also. As a fourth possibilty I would reclaim, that the synchronized keyword must be followed by a blockstatement directly or after the parenthized clause. -manfred
May 03 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Manfred Nowak wrote:
<snip>
 I know very well, that the example referenced is talking on C(++).
 
 All I wanted to say is, that Walter himself uses the pure existence 
 of an ambiguity in C(++) as an argument against C(++).
Yes. In as far as it's a weakness of these languages, but I wouldn't consider it as telling anyone "don't use C(++)".
 So, if he is not too self contained, after the above he also _must_ 
 use the pure existence of an ambiguity in D as an argument against 
 D.
<snip> Some people do admit that their creations aren't perfect. And since this particular imperfection doesn't exist in current D, this section doesn't have to influence when/where Walter admits it. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
May 03 2005
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Stewart Gordon <smjg_1998 yahoo.com> wrote:

[...]
 And since this particular imperfection doesn't exist in current D,
 this section doesn't have to influence when/where Walter admits
 it. 
I'm giving up. I am not talking of the cast ambiguity of C(++) is existing in D, but an ambiguity on the synchronized/debug statement. But now it seems hopeless to me, that only a gloom of understanding will enlighten your horizont. Thanks for your patience. -manfred
May 03 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 4 May 2005 00:19:33 +0000 (UTC), Manfred Nowak wrote:

 Stewart Gordon <smjg_1998 yahoo.com> wrote:
 
 [...]
 And since this particular imperfection doesn't exist in current D,
 this section doesn't have to influence when/where Walter admits
 it. 
I'm giving up. I am not talking of the cast ambiguity of C(++) is existing in D, but an ambiguity on the synchronized/debug statement. But now it seems hopeless to me, that only a gloom of understanding will enlighten your horizont. Thanks for your patience.
If it helps, Manfred, I understood your concerns. And your proposed solutions were reasonable too. There does exist an ambiguity in the language. With the 'debug', as Walter points out, it probably doesn't matter because bad expressions could be caught at compile time. With the synchronized statement, as you point out, ambiguities can be resolved by placing the 'target' statement inside braces. So in the end, I guess it would not be a high priority need to address these ambiguities prior to v1.0 -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v2.05 released 02/May/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 4/05/2005 10:36:58 AM
May 03 2005
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Derek Parnell wrote:
 On Wed, 4 May 2005 00:19:33 +0000 (UTC), Manfred Nowak wrote:
<snip>
I'm giving up. I am not talking of the cast ambiguity of C(++) is 
existing in D, but an ambiguity on the synchronized/debug statement.
Sorry if I misunderstood. We must have been talking at cross purposes from the moment the C(++) cast ambiguity was mentioned on the thread.
But now it seems hopeless to me, that only a gloom of understanding 
will enlighten your horizont.

Thanks for your patience.
If it helps, Manfred, I understood your concerns. And your proposed solutions were reasonable too. There does exist an ambiguity in the language. With the 'debug', as Walter points out, it probably doesn't matter because bad expressions could be caught at compile time.
I suppose it's OK for some ambiguities to be resolved by "if it's parseable as X, it's X, otherwise it's Y" rules. In these cases, X would be synchronized ( Expression ) Statement debug ( IntegerLiteral ) Statement debug ( Identifier ) Statement which would make synchronized (qwert) - yuiop; equivalent to synchronized (qwert) { -yuiop; } but synchronized (qwert) / yuiop; equivalent to synchronized { (qwert) / yuiop; } Is this how DMD behaves at the moment? Or does it simply fail once it's tried to parse / yuiop; as a statement?
 With the synchronized statement, as you point out, ambiguities can be resolved
by
 placing the 'target' statement inside braces. So in the end, I guess it
 would not be a high priority need to address these ambiguities prior to
 v1.0
I still consider this case worth doing something about: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/1955 (see followups for how it could be resolved) Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
May 04 2005