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

Dear Monks,

I'd like to have a counter that is boolean, so when you increment it, it should either become 0 or 1, based on it's previous value. I can do it like this:
if ($Counter == 0) { $Counter = 1; } else { $Counter = 0; }
, but I'd like to do the above in a more elegant way. Is it possible?

Replies are listed 'Best First'.
Re: Boolean counter?
by Corion (Pope) on Dec 07, 2009 at 08:06 UTC

    The xor operator will do what you want:

    $counter = $counter xor 1


    $counter ^= 1

    (tested with perl -wle "print $counter ^=1 for 1..3")

      I agree that the XOR solution is perfectly correct, but why use that instead of NOT? Isn't

       $counter = ! $counter;

      easier to read? That said, I have to admit that I like the snazzyness of the in place ^= syntax. It is hard to get more concise than that.

      - doug

        The difference is that $toggle ^= 1; leaves you with a number (0 or 1) while $toggle = !$toggle; leaves you with a boolean.

        Honestly, it sounds like the OP wants a boolean, so the easier to read negation should be used. If he wants to display the boolean, that's an outputting formatting issue to be resolved then.

Re: Boolean counter?
by ikegami (Pope) on Dec 07, 2009 at 08:08 UTC
    For starters,
    if ($toggle) { $toggle = 0; } else { $toggle = 1; }

    can be written as

    $toggle = $toggle ? 0 : 1;

    And if you wanted a bitwise toggle, you could do

    $toggle ^= 1;

    But you asked for boolean, so you want the even simpler:

    $toggle = !$toggle;
Re: Boolean counter?
by Utilitarian (Vicar) on Dec 07, 2009 at 08:06 UTC
    What you want is not a counter but a toggle, shortened using the ternary operator, but not sure if it's more elegant
    Edit...In fact Corion's solution above is way better.

    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: Boolean counter?
by GrandFather (Saint) on Dec 07, 2009 at 08:58 UTC

    Of course if you want obscure you can use $|--. Consider:

    print $|-- for 1 .. 4;



    Although I wouldn't recommend it in a context where you wish to win friends and influence people among the bossing classes.

    True laziness is hard work
Re: Boolean counter?
by Ratazong (Monsignor) on Dec 07, 2009 at 12:19 UTC
    Just to show that you can make a lot with "lookup-tables" ;-)

    $counter = (1, 0)[$counter];


      Just to make "lookup-tables" prettier. ;-)

      $counter = [ 1 => 0 ] -> [ 1 <= $counter ];

        ug, you create two variables every time you toggle it (one of which is an array!), and you rely on the undocumented values of <= returns. And the latter doesn't help make it prettier at all!
Re: Boolean counter?
by moritz (Cardinal) on Dec 07, 2009 at 08:21 UTC
    You can just use ++ to increment your counter, but when you ask for its value use $counter % 2 instead of the counter itself.

    Or if you're not interested in the numeric value 0, but rather that it's a false value, you can also use this update step:

    $counter = !$counter;
      Or if you do want the numerical value:
      $counter = !$counter || 0;
Re: Boolean counter?
by eye (Chaplain) on Dec 07, 2009 at 08:18 UTC
    One more way...

    $toggle = 1 - $toggle;
    This lacks elegance since it needs to start at 0 or 1, but it is simple.
Re: Boolean counter?
by vitoco (Friar) on Dec 07, 2009 at 12:47 UTC

    Two more approaches:

    - Using hashes:

    my %Next = ( 0 => 1, 1 => 0); my $Counter = 0; #... $Counter = $Next{$Counter};

    - Decreasing instead of increasing:

    $Counter = abs --$Counter;
      $Counter = - --$Counter;

        Don't modify a variable that you're using elsewhere in an expression. At best, it's unclear. At worse, the result is undefined.

        $toggle = - --$toggle;
        should be
        $toggle = -( $toggle - 1 );
        which can be shortened to previously mentioned
        $toggle = 1 - $toggle;
        The behaviour of that is actually not defined. You may end up with $Counter being -1, or with purple daemons coming out of your USB port, ready to chew off your fingers.
Re: Boolean counter?
by JavaFan (Canon) on Dec 07, 2009 at 12:00 UTC
    Just to prove you can use trigs to solve almost anything:
    $counter = int cos $counter * atan2(1, 0);
Re: Boolean counter?
by hdb (Monsignor) on Mar 04, 2015 at 13:07 UTC

    I cannot resist. You can also use a closure, every time you call it you get 0 or 1 alternatingly. You can create as many independent toggles as you want.

    use strict; use warnings; sub create_toggle { my $flag = 0; return sub { $flag = 1-$flag } # your favorite method here } my $toggle = create_toggle; print $toggle->()."\n" for 1..10;

    UPDATE: ...or like this

    use strict; use warnings; { package Toggler; sub new { my $flag = 0; return sub { $flag = 1-$flag } } } my $toggle = new Toggler; print $toggle->()."\n" for 1..10;
Re: Boolean counter?
by rowdog (Curate) on Dec 07, 2009 at 22:11 UTC

    I tend to use $toggle *= -1;

    Update: I stand corrected, thanks LanX. I often use that for alternating rows but it's wrong here.

      well it's a toggle but can't be used as boolean as the OP wanted , since 0*-1=0

      Cheers Rolf

      Your idea works the following way - even if it doesn't look as elegant any more:

      $toggle = -1 * ($toggle - 0.5) + 0.5;
      Rata (loving this thread)