Suppose I have a complex chain of ifs. Now I want to be sure that one of the conditions are triggered, so I add the final line to notify me when nothing was triggered.
if condition1 ...
else if condition2 ...
else if condition3 ...
else print( "Ooops nothing triggered" )
Since I only want to print this in DEBUG mode, I wrap the final line
#if DEBUG
else print( "Ooops nothing triggered" )
#endif
and I get the strangest errors. "Closure expression is unused" and "Expected expression".
Here is some simple working code to illustrate with.
let x = Int ( arc4random_uniform ( 100 ) ) - 50
// This works
if x > 0 { print ( "Positive" ) }
else if x < 0 { print ( "Negative" ) }
else { print ( "Oops - neither" ) }
// After adding the #if this does not compile
if x > 0 { print ( "Positive" ) }
else if x < 0 { print ( "Negative" ) }
#if DEBUG
else { print ( "Oops - neither" ) }
#endif
Obviously Swift's conditional compilation here fails. I wonder why and ask how to to do this so that the test is only applied in DEBUG mode?
FWIW I am not interested in e.g. using switch - the actual logic is complex. How to do this with ifs and else ifs if possible please?
These #ifs don't really work like those preprocessor directives in C. They
According to the grammar, the syntax of these directives are the following:
if-directive-clause → if-directive compilation-condition statements(opt)
elseif-directive-clauses → elseif-directive-clause elseif-directive-clauses(opt)
elseif-directive-clause → elseif-directive compilation-condition statements(opt)
else-directive-clause → else-directive statements(opt)
if-directive → #if
elseif-directive → #elseif
else-directive → #else
endif-directive → #endif
Note that an if-directive-clause consists of #if, then a compilation-condition, then some statements. Not just anything, but statements.
else { print ( "Oops - neither" ) }
is not a statement (or a list of statements).
How about putting the #if inside the else block? That is guaranteed to be a statements:
if x > 0 { print ( "Positive" ) }
else if x < 0 { print ( "Negative" ) }
else {
#if DEBUG
print ( "Oops - neither" )
#endif
}
Related
Can anyone explain following piece of code in https://github.com/simondeziel/custom-nagios-plugins/blob/master/plugins/check_megaraid_sas . (line num 220-223)
Why this code is there
} elsif ( $slotnumber != 255 ) {
$pdbad++;
$status = 'CRITICAL';
}
It makes sense to look at the complete section:
PDISKS: while (<PDLIST>) {
if ( m/Slot Number\s*:\s*(\d+)/ ) {
$slotnumber = $1;
$pdcount++;
} elsif ( m/(\w+) Error Count\s*:\s*(\d+)/ ) {
if ( $1 eq 'Media') {
$mediaerrors += $2;
} else {
$othererrors += $2;
}
} elsif ( m/Predictive Failure Count\s*:\s*(\d+)/ ) {
$prederrors += $1;
} elsif ( m/Firmware state\s*:\s*(\w+)/ ) {
$fwstate = $1;
if ( $fwstate eq 'Hotspare' ) {
$hotsparecount++;
} elsif ( $fwstate eq 'Online' ) {
# Do nothing
} elsif ( $fwstate eq 'Unconfigured' ) {
# A drive not in anything, or a non drive device
$pdcount--;
} elsif ( $slotnumber != 255 ) {
$pdbad++;
$status = 'CRITICAL';
}
}
} #PDISKS
That section loops over a list of PDs (Primary Disks?), and I assume that this file / program output contains a human readable status for every attached device. The code looks at every line and performs some actions depending on the content of that line:
$slotnumber is assigned whenever there is Slot Number : ... in the contents of PDLIST. From looking at the logic, if there is a Firmware state line that is not Hotspare, Online or Unconfigured, and the $slotnumber is not 255, then something went horribly wrong and the status is considered CRITICAL. The number of bad PDs ($pdbad) is then increased by one.
This works,
print map { $_." x" => $_ } 1..5;
print map { ("$_ x" => $_) } 1..5;
print map { ("$_ x") => $_ } 1..5;
but this throws syntax error,
print map { "$_ x" => $_ } 1..5;
Is this documented bug, undocumented bug, or I can't see why this should not compile?
Why perl thinks this should be map EXPR, LIST instead of map BLOCK LIST
From perlref
Because curly brackets (braces) are used for several other things including BLOCKs, you may occasionally have to disambiguate braces at the beginning of a statement by putting a + or a return in front so that Perl realizes the opening brace isn't starting a BLOCK. The economy and mnemonic value of using curlies is deemed worth this occasional extra hassle.
To make your intentions clearer and to help the parser,
Say +{...} to unambiguously specify a hash reference
#list_of_hashrefs = map +{ "$_ x" => $_ }, 1..5;
Say {; ...} to unambiguously specify a code block
%mappings = map {; "$_ x" => $_ } 1..5;
Why perl thinks this should be map EXPR, LIST instead of map BLOCK LIST?
The relevant section of code is in toke.c, Perl's lexer (the below is from Perl 5.22.0):
/* This hack serves to disambiguate a pair of curlies
* as being a block or an anon hash. Normally, expectation
* determines that, but in cases where we're not in a
* position to expect anything in particular (like inside
* eval"") we have to resolve the ambiguity. This code
* covers the case where the first term in the curlies is a
* quoted string. Most other cases need to be explicitly
* disambiguated by prepending a "+" before the opening
* curly in order to force resolution as an anon hash.
*
* XXX should probably propagate the outer expectation
* into eval"" to rely less on this hack, but that could
* potentially break current behavior of eval"".
* GSAR 97-07-21
*/
t = s;
if (*s == '\'' || *s == '"' || *s == '`') {
/* common case: get past first string, handling escapes */
for (t++; t < PL_bufend && *t != *s;)
if (*t++ == '\\')
t++;
t++;
}
else if (*s == 'q') {
if (++t < PL_bufend
&& (!isWORDCHAR(*t)
|| ((*t == 'q' || *t == 'x') && ++t < PL_bufend
&& !isWORDCHAR(*t))))
{
/* skip q//-like construct */
const char *tmps;
char open, close, term;
I32 brackets = 1;
while (t < PL_bufend && isSPACE(*t))
t++;
/* check for q => */
if (t+1 < PL_bufend && t[0] == '=' && t[1] == '>') {
OPERATOR(HASHBRACK);
}
term = *t;
open = term;
if (term && (tmps = strchr("([{< )]}> )]}>",term)))
term = tmps[5];
close = term;
if (open == close)
for (t++; t < PL_bufend; t++) {
if (*t == '\\' && t+1 < PL_bufend && open != '\\')
t++;
else if (*t == open)
break;
}
else {
for (t++; t < PL_bufend; t++) {
if (*t == '\\' && t+1 < PL_bufend)
t++;
else if (*t == close && --brackets <= 0)
break;
else if (*t == open)
brackets++;
}
}
t++;
}
else
/* skip plain q word */
while (t < PL_bufend && isWORDCHAR_lazy_if(t,UTF))
t += UTF8SKIP(t);
}
else if (isWORDCHAR_lazy_if(t,UTF)) {
t += UTF8SKIP(t);
while (t < PL_bufend && isWORDCHAR_lazy_if(t,UTF))
t += UTF8SKIP(t);
}
while (t < PL_bufend && isSPACE(*t))
t++;
/* if comma follows first term, call it an anon hash */
/* XXX it could be a comma expression with loop modifiers */
if (t < PL_bufend && ((*t == ',' && (*s == 'q' || !isLOWER(*s)))
|| (*t == '=' && t[1] == '>')))
OPERATOR(HASHBRACK);
if (PL_expect == XREF)
{
block_expectation:
/* If there is an opening brace or 'sub:', treat it
as a term to make ${{...}}{k} and &{sub:attr...}
dwim. Otherwise, treat it as a statement, so
map {no strict; ...} works.
*/
s = skipspace(s);
if (*s == '{') {
PL_expect = XTERM;
break;
}
if (strnEQ(s, "sub", 3)) {
d = s + 3;
d = skipspace(d);
if (*d == ':') {
PL_expect = XTERM;
break;
}
}
PL_expect = XSTATE;
}
else {
PL_lex_brackstack[PL_lex_brackets-1] = XSTATE;
PL_expect = XSTATE;
}
Explanation
If the first term after the opening curly is a string (delimited by ', ", or `) or a bareword beginning with a capital letter, and the following term is , or =>, the curly is treated as the beginning of an anonymous hash (that's what OPERATOR(HASHBRACK); means).
The other cases are a little harder for me to understand. I ran the following program through gdb:
{ (x => 1) }
and ended up in the final else block:
else {
PL_lex_brackstack[PL_lex_brackets-1] = XSTATE;
PL_expect = XSTATE;
}
Suffice it to say, the execution path is clearly different; it ends up being parsed as a block.
I'm writing a description of R syntax, and I'd like to include some statements that include syntax errors, e.g.
if (n >= 2)
{
# if TRUE
}
else
{
# if FALSE
}
(This is a syntax error at top level because the if is complete before the else is read.) I'm trying to put this into a knitr document, but
even with error=TRUE it fails, because that option only affects run-time errors, not syntax errors. Is there some reasonable way to get this to display what would be shown if I entered it at the console? I.e.
I'd like it to display something like
if (n >= 2)
{
# if TRUE
}
else
Error: unexpected 'else' in "else"
{
# if FALSE
}
Here's a function that does part of what I want: it reproduces the output from a syntax error, but it doesn't do all the markup that knitr would do, so the formatting is wrong.
parse_with_error <- function(text) {
reportError <- function(e) {
msg <- conditionMessage(e)
line <- as.numeric(sub("^text:([[:digit:]]*):.*", "\\1", msg))
col <- as.numeric(sub("^text:[[:digit:]]*:([[:digit:]]*):.*", "\\1", msg))
cat(text[1:line], sep="\n")
if (col > 1)
cat(paste(rep(" ", col-1), collapse=""))
cat("^\n")
err <- sub("^text:[[:digit:]]*:[[:digit:]]*: ([^[:cntrl:]]*)\n.*", "\\1", msg)
parseData <- getParseData(sf)
lastToken <- parseData[nrow(parseData), "text"]
cat(paste0("Error: ", err, ' in "', lastToken, '"'), "\n")
}
text <- unlist(strsplit(text, "\n"))
sf <- srcfile("text")
tryCatch(parse(text = text, keep.source = TRUE, srcfile=sf),
error = reportError)
}
This shows how it would be used:
parse_with_error(
"if (TRUE) {
# do TRUE
}
else {
# do FALSE
}")
You can use a separate R session to evaluate the code, e.g.
```{r, engine='Rscript', error=TRUE}
if (TRUE)
{
# if TRUE
}
else
{
# if FALSE
}
```
This was the code giving me errors on Perl.
...
else if (exists($framename{$presFrame}) && (($framename{$presFrame}) < = $j))
...
here framename is a hash and presFrame is a key present in framename
Edit:
Realized if/ else syntax is a bit different in Perl as mentioned in correct answer.
I think you mean:
elsif (exists($framename{$presFrame}) && (($framename{$presFrame}) <= $j))
otherwise you'd need braces on the else clause, i.e.
else {
if(...) {
...
}
}
else if (exists($framename{$presFrame}) && (($framename{$presFrame}) < = $j))
Should be:
elsif (exists($framename{$presFrame}) && ($framename{$presFrame} < = $j))
I'm trying to write a condition for a nested if statement, but haven't found a good example of using or in if statements. The following elsif condition fails and allows the code nested beneath it to fire if $status == 6:
if ($dt1 > $dt2 ) {do one thing}
elsif(($status != 3) || ($status != 6)) { do something else}
else {do something completely different}
I'd like to avoid having another elsif for each condition as the code that actually resides here is several lines long.
Your logic is wrong and your elseif block will always return true. I think you mean to use an AND instead of an OR. Given the following snippet
foreach $status (1 .. 10) {
if (($status != 3) && ($status != 6)) {
print "$status => if\n";
} else {
print "$status => else\n";
}
}
This will output
1 => if
2 => if
3 => else
4 => if
5 => if
6 => else
7 => if
8 => if
9 => if
10 => if
If it helps your thinking, a conditional that is !something || !somethingElse can always be rewritten as !(something && somethingElse). If you apply this to your case above you'd say !(3 && 6), and seeing as a number cannot be 3 and 6 at the same time, it's always false
You said you're asking this because the code is several lines long. Fix that problem. :)
if( $dt1 > $dt2 ) { do_this_thing() }
elsif( ($status != 3) || ($status != 6) ) { do_this_other_thing() }
else { do_something_completely_different() }
Now you don't have several lines in the block and everything is next to each other. You have to figure out what those conditions will be because any value is either not 3 or not 6. :)
Perhaps you meant to use and:
if( $dt1 > $dt2 ) { do_this_thing() }
elsif( $status != 3 and $status != 6 ) { do_this_other_thing() }
else { do_something_completely_different() }
Putting print statements with var names/values into each branch can be helpful.
You could see that the elsif branch is always run, because $status != 3 || $status != 6 is true for any value of $status.