Reputation: 87
I noticed that if I replace the if-else
statement I'm using with a ternary operator I end getting a compilation error when I try and run my code. I believe the culprit is the foreach()
loop I have inside my if-else
. Do you know why the ternary operator isn't behaving the same as the if-else construct in this instance?
My code looks like this
#!/program/perl_v5.6.1/bin/perl5.6.1
use strict;
use warnings;
my $fruits_array_ref = &get_fruits();
if($fruits_array_ref != 0) {
print("$_ is a fruit.\n") foreach(@$fruits_array_ref);
}
else {
print("Maybe you like vegetables?\n");
}
sub get_fruits() {
my @fruit_list;
my $shopping_list = "/home/lr625/grocery_items";
open(my $shopping_list_h, "<", $shopping_list) or die("Couldn't open.\n");
while(my $line = <$shopping_list_h>) {
next if $line =~ /^\#/;
chomp($line);
push(@fruit_list, $line);
}
close($shopping_list_h) or die("Couldn't close.\n");
scalar(@fruit_list) > 0 ? return(\@fruit_list) : return(0);
}
My data in the grocery list looks like
# this is a header
# to my grocery list
apple
banana
grape
orange
I'm replacing the if-else
with a ?:
operator to look like this now in the main function.
my $fruits_array_ref = &get_fruits();
$fruits_array_ref != 0 ? print("$_ is a fruit.\n") foreach(@$fruits_array_ref) : print("Maybe you like vegetables?\n");
Also, for reference my error says.
syntax error at test.pl line 8, near ") foreach"
Execution of test.pl aborted due to compilation errors.
Upvotes: 3
Views: 246
Reputation: 66883
The ternary operator takes arguments before ?
and :
, see in perlop. It can evaluate an expression and use its result for this. But a loop is not an expression and cannot 'run' inside.
For a demonstration -- you could, if you insisted, call a function which will as a side effect print
sub greet { say "hello" for 1..3 }
my $x = 1;
($x == 1) ? greet() : say "bye";
Actualy doing this in production code is a different matter and would likely be a bad idea. The whole point would be to rely entirely on side effects, opposite to what we normally want to do.
To explain my comment above -- the main point of the ternary operator is to return a value, with a choice between two values, in one statement. While it is "equivalent" to an if-else, its use is (ideally) meant to be very different. So doing some other processing inside the ?:
arguments, in any way, is really an abuse of notation, a side-effect, since they are intended to produce a value to be returned. Printing out of it is opposite to the idea of producing and returning a value. This is not a criticism, the operator is used often and by many as a syntactic shortcut.
In this sense I would recommend to revert to an if-else for doing what is shown.
Upvotes: 1
Reputation: 98388
The foreach
statement modifier can only be used at the end of a statement.
Why are you using ?:
? You would normally only do that if you wanted a single result.
You could wrap the print...foreach...
in a do {...}
, or you could use map
instead of foreach
. Or just leave it as an if/else.
Upvotes: 1
Reputation: 1515
The other answers already pointed out that you can't use the ternary operator the way you tried. For the sake of completeness and to give you some sensible use cases, take a look at the following examples:
#1: Used as a subroutine argument
testSub($var eq 'test' ? 'foo' : 'bar');
Here you can see how the subroutine testSub
is called with the argument foo
if $var
equals the string test
. Otherwise testSub
will be called with bar
. This is useful because you cannot use an if-else
structure as a sub argument.
#2: Used for conditional assignment
my $result = $var eq 'test' ? 'foo' : 'bar'; # $result will contain 'foo' or 'bar'
The ternary operator is not meant as a simple replacement to an if-else
structure. Since it returns a value (here either foo
or bar
) it makes sense to also use this value. If you don't intend to use the returned value, you should go for the usual if-else
instead.
Upvotes: 4
Reputation: 241818
if-else
is a flow control structure, ?-:
is an operator that takes expressions as operands. foreach
is a flow control structure, not an expression.
You can turn any block of code into an expression by using do:
$fruits_array_ref != 0
? do { print "$_ is a fruit.\n" for @$fruits_array_ref }
: print "Maybe you like vegetables?\n";
But why?
Upvotes: 9