Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

switch, transliteration ( tr/// ) of $_ issue

by whakka (Hermit)
on Nov 18, 2008 at 15:56 UTC ( [id://724306]=perlquestion: print w/replies, xml ) Need Help??

whakka has asked for the wisdom of the Perl Monks concerning the following question:

Why doesn't this work?
switch ( $foo ) { case ( tr/I/I/ == 1 ) { $bar = 'low' } case ( tr/I/I/ == 2 ) { $bar = 'med' } case ( tr/I/I/ == 3 ) { $bar = 'high' } else { warn "Bad $_\n" } }
Yields:
Use of uninitialized value $_ in transliteration (tr///)

(Update: Because switch doesn't set $_, it filters the source code - in this case "insanely".)

Here's a test script:
#!perl! -w use strict; use Switch; my $foo = 'II'; print $foo =~ tr/I/I/, "\n"; my $bar; switch ( $foo ) { case ( tr/I/I/ == 1 ) { $bar = 'low' } case ( tr/I/I/ == 2 ) { $bar = 'med' } case ( tr/I/I/ == 3 ) { $bar = 'high' } else { $bar = "drat" } } print "Foo: $foo Bar: $bar\n"; # This works: switch ( $foo ) { case ( /I{3}/ ) { $bar = 'high' } case ( /I{2}/ ) { $bar = 'med' } case ( /I/ ) { $bar = 'low' } else { $bar = "drat" } } print "Foo: $foo Bar: $bar\n";
Thanks!

Update: Thanks kyle and jeffa, the lesson is learned - don't use Switch. (jeffa's solution indeed doesn't work - which surprised me)

Update2: moritz has it right, use the (5.010) given-when construct:

given ( $foo ) { when ( tr/I/I/ == 1 ) { $bar = 'low' } when ( tr/I/I/ == 2 ) { $bar = 'med' } when ( tr/I/I/ == 3 ) { $bar = 'high' } default { $bar = "drat" } }

Replies are listed 'Best First'.
Re: switch, transliteration ( tr/// ) of $_ issue
by kyle (Abbot) on Nov 18, 2008 at 16:06 UTC

    In Categorized Damian Modules, the author of Switch recommends against using it. It's a source filter, and it sometimes is confused by the code it's filtering. If you step through your script in the debugger, it might tell you what's going on.

      One should mention that newer versions of Perl do have a sane alternative, that's
      use 5.010; given ($foo) { when ($condition) { code } ... }

      (described in perlsyn)

Re: switch, transliteration ( tr/// ) of $_ issue
by trwww (Priest) on Nov 18, 2008 at 17:40 UTC

    Hello,

    I don't have a reply that directly relates to your code... but my advice is to just use a data structure. Why write procedural code when you don't have to?

    my $foo = 'II';
    
    my %table = (
      III     => 'high',
       II     => 'med',
        I     => 'low',
      default => 'drat',
    );
    
    my $bar = $table{$foo} or $table{default};
    
    print "Foo: $foo Bar: $bar\n";
    

    Hope this helps,

    trwww

Re: switch, transliteration ( tr/// ) of $_ issue
by jeffa (Bishop) on Nov 18, 2008 at 16:07 UTC

    Aren't you "switching" on $foo ... but checking the value of $_? Shouldn't it be this? (untested)

    switch ( $foo ) { case ( ($foo ~= tr/I/I/) == 1 ) { $bar = 'low' } case ( ($foo ~= tr/I/I/) == 2 ) { $bar = 'med' } case ( ($foo ~= tr/I/I/) == 3 ) { $bar = 'high' } else { $bar = "drat" } }

    UPDATE: nope. That appears to be right. Yuck. I'm with kyle on this one -- don't use Switch. Use an if-else block or a dispatch table instead.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      ... or the poor mans' equivalent of a switch...
      SWITCH: { $foo =~ tr/I/I/ == 1 && do { $bar = 'low'; last SWITCH; }; $foo =~ tr/I/I/ == 2 && do { $bar = 'med'; last SWITCH; }; $foo =~ tr/I/I/ == 3 && do { $bar = 'high'; last SWITCH; }; $bar = "drat"; }
      construct.

      Update Corrected typos...

      • ~= should, of course, be =~
      • Extraneous )

      A user level that continues to overstate my experience :-))
Re: switch, transliteration ( tr/// ) of $_ issue
by Roy Johnson (Monsignor) on Nov 18, 2008 at 21:53 UTC
    Or you could opt for the old-school approach, and just replace your switch with for, and your whens with if-elsifs:
    for ( $foo ) { if ( tr/I/I/ == 1 ) { $bar = 'low' } elsif ( tr/I/I/ == 2 ) { $bar = 'med' } elsif ( tr/I/I/ == 3 ) { $bar = 'high' } else { $bar = "drat" } }

    Caution: Contents may have been coded under pressure.
Re: switch, transliteration ( tr/// ) of $_ issue
by runrig (Abbot) on Nov 18, 2008 at 22:15 UTC
    my $bar = (0,'low','med','high')[$foo=~tr/I//] || 'drat'; # or my $bar; $bar = (0,'low','med','high')[tr/I//] || 'drat' for $foo;

      No real advantage, but for completeness:

      my ($bar) = map +(0,'low','med','high')[tr/I//] || 'drat', $foo; # or my ($bar) = map qw(0 low med high)[tr/I//] || 'drat', $foo;

      qw helps, and "0" is false...

      --
      If you can't understand the incipit, then please check the IPB Campaign.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://724306]
Approved by kyle
Front-paged by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (3)
As of 2024-04-16 21:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found