Two disadvantages of the "plain old" method of subroutine argument passing are that (1) even though you can modify its elements, you can't modify an array or hash argument itself, and (2) copying an array or hash into @_ takes time. Both of these disadvantages can be overcome with references (see Item 30). Passing arrays and hashes by reference is straightforward: Print out the contents of an array, with each element prefixed by an index.
Find all the elements in a hash that aren't in an array.
The second example also returns a reference to a hash. It would be considerably less efficient to return %hash itself. Returning "just" the hash variable actually results in %hash being unwound into a list of key-value pairs, which are then used to construct an entirely new hash. This is much less efficient than returning a reference to the hash that already existsand which will otherwise be destroyed when the subroutine exits. Think of it as recycling. In the days before references, programmers sometimes resorted to passing typeglobs (see Item 57) when it was necessary to pass an array or hash by reference. Here's an example of using typeglobs to construct a subroutine that takes two arrays by reference (using Perl 5 syntax): Take two arguments the old-fashioned (and inefficient) way. Note that the arguments are passed as typeglobs ( *a , *b ), not references ( \@a , \@b ).
There is no reason to write code like this any more, but if you deal with a lot of legacy code, you may run into something like it. Using local * on reference argumentsSubroutines that take arguments by reference for speed sometimes lose some of their speed advantage as they continually dereference those arguments. The syntax also becomes distracting and hard to follow. Here's a subroutine that takes two arrays and returns a list made up of the largest elements from the arrays compared pairwise: Return maximum elements from two arrays, comparing pairwise.
Those doubled dollar signs aren't very pretty, are they? One way to get around this problem is to alias variables to the arrays. Assigning a reference to a typeglob has the effect of creating an aliased variable of the type appropriate to the reference: Return maximum elements from two arrays, comparing pairwise (improved version).
This subroutine is somewhat easier to read once you get past the somewhat strange -looking first assignment. It will probably execute faster than the first version. When I tested this example, I saw about a 10 percent speed increasenot enormous , but significant. Passing filehandlesPassing filehandles and dirhandles is a somewhat awkward matter in Perl. In the years B.R. (before references), programmers had to use typeglobs to pass filehandles and dirhandles. Once references were introduced, the FileHandle and DirHandle modules improved the situation somewhat. It also became possible to pass references to typeglobs, which is more efficient than passing "bare" typeglobs. The recently introduced IO module and the so-called *FOO{BAR} (typeglob subscript) syntax have added still more options. Let's look at all of them in brief. The filehandle typeglob looks like this (Perl 5 syntax again): sub fh_by_typeglob { local *FH = shift; print FH "your message here\n"; } open FILE, ">temp.txt" or die $!; fh_by_typeglob *FILE; This trusty old mechanism is still in widespread use, because it is well known and it is relatively efficientan extra symbol table lookup or two is insignificant if most of what's going on is I/O, and it does take time to load a module like FileHandle . The FileHandle module creates objects that can be treated like ordinary scalars: use FileHandle; sub fh_by_FileHandle { my $fh = shift; print $fh "your message here\n"; } $file = new FileHandle "temp.txt", "w"; die "couldn't open: $!" unless $file; fh_by_FileHandle $file; The syntax for passing typeglobs by reference shouldn't look all that surprisingbut notice that you don't have to dereference a globref to use it as a filehandle:
Recent versions of Perl now include the IO classes, which are intended to eventually replace FileHandle , DirHandle , and other earlier I/O classes. IO::File works very much like FileHandle : use IO::File; sub fh_by_IOFile { my $fh = shift; print $fh "your message here\n"; } $file = new IO::File "temp.txt", "w"; die "couldn't open: $!" unless $file; fh_by_IOFile $file; And, finally, recent versions of Perl have a new kind of referencethe ioref . An ioref is a reference to a structure internal to Perl that describes a filehandle and/or dirhandle. You can create an ioref with the *FOO{BAR} syntax and then use it like a filehandle or an object from IO::File :
By now you're probably wondering which of these methods you should use. Unfortunately, this is one of those cases where I can't offer you any firm guidance. I will make a few suggestions, though:
The situation for dirhandles is similar. You can use the DirHandle module, iorefs (e.g., $ioref = *DIRH{IO} ), or a dirhandle typeglob. You can also use the newer IO::Dir class. Which one you choose will depend on the circumstancesthere are no hard and fast rules. However, there will not be too many occasions when you will actually want to pass dirhandles to subroutines. Usually, the pathname is more appropriate, because you can't (not yet, anyway) use a dirhandle in place of a directory pathname: Recursing through a directory tree
Looks like a lot of work, doesn't it? If you are trying to traverse a directory tree, you may not need to go to all this troublecheck out the File::Find module first. |