Documenting else's greed

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Documenting else's greed

Hugh Parsonage
I was initially pretty shocked by the result in this question:
https://stackoverflow.com/questions/57527434/when-do-i-need-parentheses-around-an-if-statement-to-control-the-sequence-of-a-f

Briefly, the following returns 0, not 3 as might be expected:

if (TRUE) {
    0
} else {
    2
} + 3

At first I thought it the question was simply one of syntax
precedence, but I believe the result is too surprising to not warrant
note in the documentation of Control. I believe the documentation
should highlight that the `alt.expr` is demarcated by a semicolon or
newline and the end of a *statement*, not a closing brace per se.

Perhaps in the paragraph starting 'Note that it is a common mistake to
forget to put braces...' it should end with. "Note too that it is the
end of a *statement*, not a closing brace per se, that determines
where `alt.expr` ends. Thus if (cond) {0} else {2} + 2 means if (cond)
{0} else {2 + 2} not {if (cond) {0} else {2}} + 2."

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Documenting else's greed

Duncan Murdoch-2
On 16/08/2019 12:36 p.m., Hugh Parsonage wrote:

> I was initially pretty shocked by the result in this question:
> https://stackoverflow.com/questions/57527434/when-do-i-need-parentheses-around-an-if-statement-to-control-the-sequence-of-a-f
>
> Briefly, the following returns 0, not 3 as might be expected:
>
> if (TRUE) {
>      0
> } else {
>      2
> } + 3
>
> At first I thought it the question was simply one of syntax
> precedence, but I believe the result is too surprising to not warrant
> note in the documentation of Control. I believe the documentation
> should highlight that the `alt.expr` is demarcated by a semicolon or
> newline and the end of a *statement*, not a closing brace per se.
>
> Perhaps in the paragraph starting 'Note that it is a common mistake to
> forget to put braces...' it should end with. "Note too that it is the
> end of a *statement*, not a closing brace per se, that determines
> where `alt.expr` ends. Thus if (cond) {0} else {2} + 2 means if (cond)
> {0} else {2 + 2} not {if (cond) {0} else {2}} + 2."



I agree this is surprising, and should perhaps be pointed out in the
docs, but I don't think your suggestion is quite right.  { 2 } + 3 is a
legal expression.  It doesn't have to be the end of a statement that
limits the alt.expr, e.g. this could be one big statement:


  { if (TRUE) {
       0
     } else {
       2
     } + 3 }

What ends alt.expr is a token that isn't collected as part of alt.expr,
not just a semicolon (which separates statements) or a newline.  I don't
know how many of those there are, but the list would include at least
semicolon, newline, }, ), ], and maybe others.

Duncan Murdoch

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Documenting else's greed

Georgi Boshnakov
In reply to this post by Hugh Parsonage
Indeed, an example in the documentation about this feature would be helpful, may be the one Hugh used. If an explanation is deemed appropriate, I would suggest including something along the lines of the following
(after the second paragraph of the Details section for if/while/etc.).

===============

In these constructs the opening braces, if any, are part of the expression to be evaluated, not syntax delimiters.
In particular, the expression does not necessarily end with the closing brace. For example, '{2} + 3' and '2 + 3' are equivalent expressions, so the first command below gives 0, not 3.

> if(TRUE) 0 else {2} + 3
[1] 0
> if(TRUE) 0 else 2 + 3
[1] 0
================

In practice, this confusion appears mainly in the 'else' part of 'if' constructs. But it is not limited there. For example, this defines a function with body x^2 + 1, for the same reasons, although one might expect an error.

> f <- function(x){x^2} + 1
> f(2)
[1] 5
> as.character(body(f))
[1] "+"             "{\n    x^2\n}" "1"            
>

Georgi Boshnakov

------------------------------

Message: 5
Date: Sat, 17 Aug 2019 02:36:39 +1000
From: Hugh Parsonage <[hidden email]>
To: R-devel <[hidden email]>
Subject: [Rd] Documenting else's greed
Message-ID:
        <[hidden email]>
Content-Type: text/plain; charset="utf-8"

I was initially pretty shocked by the result in this question:
https://stackoverflow.com/questions/57527434/when-do-i-need-parentheses-around-an-if-statement-to-control-the-sequence-of-a-f

Briefly, the following returns 0, not 3 as might be expected:

if (TRUE) {
    0
} else {
    2
} + 3> f
function(x){x^2} + 1
> body(f)
{
    x^2
} + 1
> f(2)
[1] 5

At first I thought it the question was simply one of syntax
precedence, but I believe the result is too surprising to not warrant
note in the documentation of Control. I believe the documentation
should highlight that the `alt.expr` is demarcated by a semicolon or
newline and the end of a *statement*, not a closing brace per se.

Perhaps in the paragraph starting 'Note that it is a common mistake to
forget to put braces...' it should end with. "Note too that it is the
end of a *statement*, not a closing brace per se, that determines
where `alt.expr` ends. Thus if (cond) {0} else {2} + 2 means if (cond)
{0} else {2 + 2} not {if (cond) {0} else {2}} + 2."




------------------------------

Message: 6
Date: Fri, 16 Aug 2019 16:31:15 -0400
From: Duncan Murdoch <[hidden email]>
To: Hugh Parsonage <[hidden email]>, R-devel
        <[hidden email]>
Subject: Re: [Rd] Documenting else's greed
Message-ID: <[hidden email]>
Content-Type: text/plain; charset="utf-8"; Format="flowed"

On 16/08/2019 12:36 p.m., Hugh Parsonage wrote:

> I was initially pretty shocked by the result in this question:
> https://stackoverflow.com/questions/57527434/when-do-i-need-parentheses-around-an-if-statement-to-control-the-sequence-of-a-f
>
> Briefly, the following returns 0, not 3 as might be expected:
>
> if (TRUE) {
>      0
> } else {
>      2
> } + 3
>
> At first I thought it the question was simply one of syntax
> precedence, but I believe the result is too surprising to not warrant
> note in the documentation of Control. I believe the documentation
> should highlight that the `alt.expr` is demarcated by a semicolon or
> newline and the end of a *statement*, not a closing brace per se.
>
> Perhaps in the paragraph starting 'Note that it is a common mistake to
> forget to put braces...' it should end with. "Note too that it is the
> end of a *statement*, not a closing brace per se, that determines
> where `alt.expr` ends. Thus if (cond) {0} else {2} + 2 means if (cond)
> {0} else {2 + 2} not {if (cond) {0} else {2}} + 2."



I agree this is surprising, and should perhaps be pointed out in the
docs, but I don't think your suggestion is quite right.  { 2 } + 3 is a
legal expression.  It doesn't have to be the end of a statement that
limits the alt.expr, e.g. this could be one big statement:


  { if (TRUE) {
       0
     } else {
       2
     } + 3 }

What ends alt.expr is a token that isn't collected as part of alt.expr,
not just a semicolon (which separates statements) or a newline.  I don't
know how many of those there are, but the list would include at least
semicolon, newline, }, ), ], and maybe others.

Duncan Murdoch


______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel