Somehow, I just never ended up investigating use of local() with Perl. I've been using lexical scope ever since I learned it existed, and before that I (very briefly) didn't use strict, so no explicit declarations were needed. Good ol' local() just never figured into it.

I've been investigating the differences between local() and my() recently, because a friend asked me some questions about lexical scope and how exactly my() differs from local(). Somewhere along the way in the last few years, I'd picked up the textbook definition of local(), but that didn't tell me much about it — though I did get enough from my hazy memory and a quick refresher on how dynamic and lexical scoping each affect language implementation to be able to offer somewhat useful answers to my friend. The clearest usage advice I've seen about local(), in several venues, is "Don't."

I was reading a quick Perl I/O howto someone I know wrote about slurping file contents into a scalar variable, newlines and all, today. It suggested a methodology something like the following:

my $foo = $/; undef $/; my $bar = <>; $/ = $foo;

This is probably the knee-jerk, simple method of accomplishing that feat that comes immediately to mind for most when not really thinking about the fact that TIMTOWTDI. I thought there should be a better way, though, and the second option that came to mind was something like this:

my $foo; $foo .= $_ while <>;

Another that came to mind immediately looks something like this (though I don't like it much):

my $foo; my @bar = <>; $foo .= $_ foreach @bar;

What wouldn't have occurred to me at all if I hadn't been thinking about local() a lot recently is this one:

my $foo; { local $/; $foo = <>; }

. . . which strikes me as a surprisingly elegant rewrite of the file-slurping methodology in the howto.

I decided to kick around in PerlMonks and see what I could find that might address using local() for scalar context file content assignment to a variable, and came across Slurp a file, wherein Merlyn whipped out this gem (slightly modified to fit my foregoing example style):

my $foo = do { local $/; <> };
Edit: It has been pointed out in the ensuing discussion that this code essentially loads two copies of the contents of <> into memory for a brief moment, and preceding example where $foo is declared on its own line, then assigned explicitly in the unnamed block without the use of do, uses less system resources.

There was discussion of using join(), with or without local $/, for various levels of safety and performance (complete with benchmarks), and of using sysread(), which is of course problematic on some OSes but blazing fast (as system calls often are, all else being equal).

. . . but I really rather like Merlyn's version of what I came up with while contemplating the problem on my own. Here's the question that comes to mind:

How did I never read anything about the usefulness of local() for such purposes before this? Am I living under a rock?

print substr("Just another Perl hacker", 0, -2);
- apotheon
CopyWrite Chad Perrin

Replies are listed 'Best First'.
Re: local() for scalar file slurping
by ikegami (Patriarch) on Jul 28, 2006 at 21:19 UTC

    local provides a limited form of scoping for package variables. When you want to change a package variable (such as $/) temporarily, use local, not a temporary variable. That way, the variable's value will be restored even if the scope is exited using die.

    { local $var; ...; }
    is very similar (as observed when $var is magical) to
    { my $anon = $var; undef $var; ...; $var = $anon; }
    except $var = $anon; will execute even if the scope is exited using die. (Also, it's probably more efficient).

    By the way,
    my $foo = do { local $/; <> };
    is quite neat, but it requires twice as much memory as
    my $foo; { local $/; $foo = <>; }

      requires twice as much memory

      Why?

      print substr("Just another Perl hacker", 0, -2);
      - apotheon
      CopyWrite Chad Perrin

Re: local() for scalar file slurping
by holli (Abbot) on Jul 28, 2006 at 20:35 UTC
    Am I living under a rock?
    No, you just have your blind spots. As we all have.

    And you identified one of it. Congrats :)


    holli, /regexed monk/

      Thanks!

      As simple a realization as it is, this was an exciting epiphany for me — nowhere near the level of the epiphany I enjoyed when I first grokked closures, but of the same flavor. I think that had something to do with the fact that I went from never having used, or had reason to use, a feature of the language, to suddenly recognizing that feature's intriguing possibilities. Perl's great that way. So is learning a new language, but Perl's kinda like learning a new language every few months.

      print substr("Just another Perl hacker", 0, -2);
      - apotheon
      CopyWrite Chad Perrin

Re: local() for scalar file slurping
by bobf (Monsignor) on Jul 30, 2006 at 05:23 UTC

      Thanks for the list. There's some good reading in there.

      How does one become a pedagogue, anyway? I'm curious.

      print substr("Just another Perl hacker", 0, -2);
      - apotheon
      CopyWrite Chad Perrin

        It helps if one is something of a pedant. (I can say that since I am the "charter member" of the group...) ;-)

        Seriously, according to our usergroup,

        The pedagogues are those brave souls who have decided to focus on teaching others through managing the tutorials section.

        demerphq has stated (and I totally agree) that "the purpose of pedagogues is to aggregate, edit and commission" Tutorials.

        So, a desire to help with such is the primary prerequisite. I don't know if any formal guidelines such as a minimum rank have been established, although I would probably say that the minimums required to join other groups are probably a pretty good threshold. Other than that... humbly petition one of the gods. :-)

        HTH,

        planetscape
Re: local() for scalar file slurping
by revdiablo (Prior) on Jul 29, 2006 at 15:44 UTC
    How did I never read anything about the usefulness of local() for such purposes before this? Am I living under a rock?

    Indeed, I was blind to local for much of my early Perl years (yes, I literally mean years) also. I read the warnings to never use it, and I took them dead seriously. Once I started toying more, though, I found that there are indeed some good uses of local. I consider what you've shown one of them.

    Another one is that you can localize a particular element in an array or a hash. Much as with local in general, this has many bad uses and a few good ones, but it's still a neat trick. Example:

    my %hash = qw(one 1 two 2); { local $hash{one} = $hash{one}; $_++ for values %hash; print "$hash{one} $hash{two}\n"; # prints "2 3" } print "$hash{one} $hash{two}\n"; # prints "1 3"

    Notice the change to $hash{two} is permanent, but the change to $hash{one} is localized. Pretty cool, eh?

Re: local() for scalar file slurping
by sh1tn (Priest) on Aug 09, 2006 at 10:10 UTC
    TMTOWTDI: force list context
    my $file_data = join q{}, @{[<$fh>]};