sid_com
sid_com

Reputation: 25117

Differences beteween switch- and if-statements

Do these two statements behave equally or could they yield different results?

if ( ... ) {...}
elsif( ... ) {... }
elsif( ... ) { ... }
else { ... }

.

given ( ... ) {
    when ( ... ) { ... }
    when ( ... ) { ... }
    default { ... }
}

I've found the problem - with a modified ninth "when" it works now.

...
no warnings qw(numeric);
my $c = &getch();

given ( $c ) {
when ( $c == $KEY_LEFT and 1 > 0 ) { say 1; say $c }
when ( $c == $KEY_RIGHT ) { say 2; say $c } 
when ( $c eq "\cH" or $c eq "\c?" ) { say 3; say $c } 
when ( $c eq "\cC" ) { say 4; say $c } 
when ( $c eq "\cX" or $c eq "\cD" ) { say 5; say $c } 
when ( $c eq "\cA" ) { say 6; say $c } 
when ( $c eq "\cE" ) { say 7; say $c } 
when ( $c eq "\cL" ) { say 8; say $c } 
when ( not( not $SpecialKey{$c} ) ) { say 9; say $c } 
when ( ord( $c ) >= 32 ) { say 10; say $c } 
default { say 11; say $c }
}

if ( $c == $KEY_LEFT and 1 > 0 ) { say 1; say $c }
elsif ( $c == $KEY_RIGHT ) { say 2; say $c } 
elsif ( $c eq "\cH" or $c eq "\c?" ) { say 3; say $c } 
elsif ( $c eq "\cC" ) { say 4; say $c } 
elsif ( $c eq "\cX" or $c eq "\cD" ) { say 5; say $c } 
elsif ( $c eq "\cA" ) { say 6; say $c } 
elsif ( $c eq "\cE" ) { say 7; say $c } 
elsif ( $c eq "\cL" ) { say 8; say $c } 
elsif ( $SpecialKey{$c} ) { say 9; say $c } 
elsif ( ord( $c ) >= 32 ) { say 10; say $c } 
else { say 11; say $c }

close TTYIN;

Upvotes: 4

Views: 1729

Answers (5)

Dave Cross
Dave Cross

Reputation: 69314

Adding another answer as I've just realised what the real problem is.

Your "when ($SpecialKey{$c})" is equivalent to "if ($_ ~~ $SpecialKey{$c})". And as "given" has set $_ to $c that's the same as "if ($c ~~ $SpecialKey{$c})". When comparing two scalar values (and I assume that's what we've got here) the smart match operator looks for values that are numbers and uses "eq" or "==" as appropriate.

So your code is effectively equivalent to "if ($c == $SpecialKey{$c})". And that's completely different to "if ($SpecialKey{$c})".

Upvotes: 1

David W.
David W.

Reputation: 107060

Whatever you can do with the given/when, you can do with if/elsif/else. The idea is that when/given is suppose to be easier to read, and can automatically use smartmatching by default while you have to specify smart matching with the if/else statement.

I didn't parse through your code to make sure they're exact equivalents, but it looks like you've got more or less the right idea about if/elsif/else and given/when.

I never really understood the desire for what was referred to as the switch statement. It was something Perl coders always complained about -- the lack of a switch statement in Perl. Maybe it's a C thing that most Perl developers fondly remember. But I never found the if/elsif/else statements that bad.

What really confuses me is that when they finally implemented the switch statement, they didn't call it switch. Why the heck not?

And why say instead of printnl?

And, why last and next instead of break and continue. Why not simply use the standard names that other languages already use?

But enough of this Seinfeld style whining...

As davorg said, there's a big difference between a hash key that doesn't exist, a hash key that exists, but isn't defined, and a hash key that's defined, but gets evaluated to false:

For example:

use strict;
use warnings;
no warnings qw(uninitialized);

my %hash;
$hash{FOO} = "bar";

if (not exists($hash{BAR})) {
print "\$hash{FOO} doesn't exist\n";
}
if (not defined($hash{BAR})) {
print "\$hash{BAR} is undefined\n";
}
if (not $hash{BAR}) {
print "\$hash{BAR} evaluates to false\n";
}
if ($hash{BAR} eq undef) {
print "\$hash{BAR} is equal to 'undef'\n";
}

You can see that $hash{BAR} doesn't even exist as a key in the %hash hash, but it is also undefined, and it evaluates as false. And, you can also see that it also evaluates as undef (notice I had to set no warnings qw(uninitialized); to prevent it from complaining about $hash{BAR} being uninitialized in my last if statement).

However, if I do this:

$hash{FOO} = bar;
$hash{BAR} = undef;

The first if statement no longer evaluates as true because the key BAR now does exist in the hash, but the value is still undefined and still evaluates as false.

And, if I did this:

$hash{FOO} = bar;
$hash{BAR} = 0;

$hash{BAR} now exists as a key in %hash, and it is no longer undefined, but it still evaluates as false.

I like simply being able to say this:

if (not $hash{BAR}) {

because it is short and sweet, and probably does what I want. However, I do have to understand the difference between existence of a key in a hash, evaluation to false, and not being defined as three separate things. It can be important if you have a subroutine that could return a NULL string or zero value:

if (not foo($bar)) {
    die qq(Error of some sort\n);
}

sub foo {
    $bar = <FOO> or return;
    return chomp($bar);
}

If there's a blank line in my file, it'll return a NULL string, but the subroutine will still return a defined value. The above probably does not do what I want.

Upvotes: 3

&#216;yvind Skaar
&#216;yvind Skaar

Reputation: 2328

given / when has implicit smart matching:

Most of the power comes from implicit smart matching:

  1. when($foo)

is exactly equivalent to

  1. when($_ ~~ $foo)

I don't think if/else does that(?)

See perlsyn

EDIT: Guess this doesn't really matter when using given/when the way OP is, but it still answers the question :)

Upvotes: 0

Dave Cross
Dave Cross

Reputation: 69314

Your supposedly "fixed" version now does different things in the two versions of the code. Checking if a key exists in a hash is completely different to checking whether the associated value is true.

There are three different truth values you can get from a hash - whether the key exists in the hash, whether the associated value is defined and whether the associated value is true or false. This code should demonstrate the difference between the three:

#!/usr/bin/perl

use strict;
use warnings;

my %hash = (
  key1 => undef,
  key2 => 0,
  key3 => 1,
);

foreach (qw(key1 key2 key3 key4)) {
  check_key($_);
}

sub check_key {
  my $k = shift;

  print "Key $k ";
  if (exists $hash{$k}) {
    print 'exists. ';
  } else {
    print "doesn't exist. ";
  }

  print 'Value ';

  if (defined $hash{$k}) {
    print 'is defined ';
  } else {
    print 'is not defined ';
  }

  print 'and is ';

  if ($hash{$k}) {
    print "true\n";
  } else {
    print "false\n";
  }
}

Upvotes: 4

Thariama
Thariama

Reputation: 50832

They behave totally equal.

Upvotes: 0

Related Questions