(Note: below I talk about XML but it's not really all that relevant)

One thing it's useful to do while writing SAX modules is to store up the characters we've seen and process them in a start/end element handler. We do this because a SAX processor doesn't guarantee to us that it'll return all the characters at a time - it will often split on buffer boundaries, or entities, or CDATA boundaries.

So in my SAX handler I do:

sub characters { my ($self, $chars) = @_; $self->{buffered_text} .= $chars->{Data}; ... }
Now at some point you'll want to retrieve this text, and reset the buffer to the empty string. The really simple way to do this, that everyone will probably do on their first attempt is as follows:
sub get_buffered_text { my $self = shift; my $text = $self->{buffered_text}; $self->{buffered_text} = ''; return $text; }
But it occured to me - perl can swap variables without using a temporary variable using ($x,$y) = ($y,$x), and I wondered if I could (ab)use that. It turns out you can:
sub get_buffered_text { my $self = shift; (($_, $self->{buffered_text}) = ($self->{buffered_text}, ''))[0]; }
I was going to post this under obfuscation, because it probably belongs there, and it's so horrible that I'm actually not going to use it in production, but I thought some people here might find it neat to save on using a temp variable for this sort of thing.

Update: The $_ used there was a golfing optimisation. It works fine with undef or just about anything in that position.

Replies are listed 'Best First'.
(tye)Re: Swapping object variables
by tye (Sage) on Jan 24, 2002 at 20:27 UTC

    In this specific case, you might like:     return delete $self->{buffered_text}; but several times I have felt the desire to have a "delayed assigment" syntax much like the post increment and decrement operators. That is, an assignment operator that would return the value of the variable from before the assignment takes effect.

    For example, without advocating it as a reasonable syntax choice, consider =: as meaning "delayed assigment" and .=: being the delayed version of .=, etc.

    my $old_value= $value .=: $more_text; # and return $self->{buffered_text} =: "";

    But I've wanted this infrequently enough and found the creation of a temporary variable to be reasonable enough, that I'm not pushing for such an addition.

    BTW, I'd use your original version of the code over your last version in production. (:

            - tye (but my friends call me "Tye")
      I did consider delete, except in this particular case (where everthing is ".="), undef/delete causes "Use of uninitialized variable" warnings, unless unset $^W, which I don't like doing, or use 5.6's lexical warning pragmas, and a CPAN author can't really mandate 5.6.

      Thanks though.

        One would think so, eh? But I actually tested that before I posted:

        #!/usr/bin/perl -w use strict; my %h; $h{okay} .= "Hello"; # No warning (for me, at least) warn "----\n"; $h{warn}= $h{warn} . "Hello"; # Gives a warning
        produces
        ---- Use of uninitialized value in concatenation (.) at line 6.
        But perhaps this isn't true in some older versions of Perl (I only tested v5.6.0).

                - tye (but my friends call me "Tye")
      Something I've always wanted is a 'left associative =' which would do exactly that:
      my $text =< $self->{buffered_text} =< '';


        p
Re (tilly) 1: Swapping object variables
by tilly (Archbishop) on Jan 24, 2002 at 21:54 UTC
    Using $_ there is a Bad Idea, since you will wipe out whatever $_ is currently set, even if you are being called from a different package namespace. This is Not Good.

    Just stick a lexically scoped variable there and all will be well.

Re: Swapping object variables
by chromatic (Archbishop) on Jan 24, 2002 at 23:22 UTC
    I like this idiom in my standard test tied filehandle code:
    my $self = shift; return substr($$self, 0, length($$self), '');
    That does assume you have four-arg substr available, though it predates 5.6.
Re: Swapping object variables
by herveus (Prior) on Jan 24, 2002 at 21:41 UTC
    Howdy!

    That looks a lot like the one-line select cited in Camel 2 (at least) for setting $| on a filehandle. That construct is there labeled as "curious and bizarre".

    select (select(STDERR), $|=1)[0];
    yours,
    Michael