Friday, January 9, 2009

Questions Regarding Perl References In Linux And Unix

Hey There,

Today's post is a follow up to our post, from earlier this week, regarding understanding Perl variable references. The feedback was generally positive, but one particular question was asked by quite a few people. And that question was:

If there's nothing new under the sun, then how can there be more things in heaven and earth than are dreamt of in anyone's philosophy?

To be quite honest, I have no idea. I quit pondering the meaning of "it all" when I was introduced to nihilism at the age of 18, which, consequently, fit in perfectly with my intensive practical application of Onanism. My philosophy was both fun "and" meaningless ;)

But, that wasn't the real question. I just went off on a tangent there for a moment, as it's my wont to do. Apologies for any trauma caused by the high-brow self-abuse joke. It has nothing to do with Linux, Unix or Perl unless you, like Sammy Hagar, consider it all mental masturbation ;)

The real question on people's minds was this:

What purpose, at all, do references in Perl serve, and why would I ever want to complicate things by using them?

This is a valid question; especially if you aren't hard-core into Perl or only use it as a work aide. Quite frankly, I, myself, rarely have any use for references. But here's a quick rundown of a few reasons why it's good to know them and understand how they work (Note that, in Perl, references and pointers - as they're more commonly known in programming languages like C - are terms that often get used interchangeably. For our purposes, they both mean the same thing).

1. For folks who've been using Perl since version 4 and earlier, references were an absolute "must" to understand if you wanted to do any semi-complex work with subroutines. At that point in time, you could only pass scalar variables as arguments to a subroutine. This made it impossible for you to, for instance, pass an array, hash or more complex variable as an argument to your subroutine. Thus, the reference made it possible for you to pass an array or hash as an argument to your subroutine, since the Perl reference to either was (and is) always a scalar variable. I think this is the one issue that is really being addressed when folks question the usefulness of Perl references these days. As the below scriptlet shows, the days of only being able to pass a scalar variable to your subroutines are long since gone. The language has been improved upon and, now, you can pass arrays, hashes, etc, directly to your subroutines as arguments, without having to make use of scalar references to them (more on that in point 2). Check out the following for a demonstration of how Perl can now handle these types of arguments (a few of you actually already have this in your mail, as I put it together to demonstrate this principle earlier this week in response to several emails - I aim to please :):

host # cat shell.pl
#!/usr/bin/perl

$bfile = "what the heck";
@bfile = qw(what the heck);

scalarsub($bfile);
arraysub(@bfile);

sub scalarsub {

my $file=shift;
print "SCALAR: F $file\n";
}

sub arraysub {

my @file=@_;
foreach $item (@file) {
print "ARRAY: F $item\n";
}
}
--- test run of script ---------
host # ./shell.pl
SCALAR: F what the heck
ARRAY: F what
ARRAY: F the
ARRAY: F heck


As you can see, above, today's Perl doesn't require you to reference non-scalar variables if you want to pass them as arguments to a subroutine.

2. References still do have a place in Perl, even when it comes to subroutines. If it sounds like I'm contradicting what I just wrote, please allow me to dig myself further into a hole... I mean, explain ;)

Consider, if you will, the following situation in which making use of Perl references would actually save you considerable time and, probably, a gray hair or two. If you have a simple subroutine (like in our scriptlet above), it is very easy to pass it several scalar arguments (assuming no restrictions on the amount of arguments you can pass) and, logically, any amount, and/or combination, of different types of variables. But, what happens when you call your subroutine with arguments like this?:

@array1 = qw(1 2 3 4 5);
@array2 = qw(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19);
@array3 = qw(1 2 3);
mynewsubroutine(@array1, @array2, @array3);
@_ = 1 2 3 4 5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 1 2 3;
<-- within your subroutine.
my (@array1,@array2,@array3) = @_;

Now, while there are more than several clever ways you can get around parsing this input (which is one of the great things about Perl), it can be difficult to process this sort of input within the subroutine; especially if the arrays, themselves, are of variable and/or undetermined size (perhaps @array1 contains 5 scalar variables, @array2 contains 19 scalar variables and @array3 contains an additional 3 scalar variables - we'll, again, stay away from passing arrays of hashes of arrays for now ;). This can constitute a lot of work on the programmer's part to craft the subroutine in such a way that it handles all of the input and keeps it separated, correctly, into the three groups, since the totality of the arguments passed to a subroutine can be referenced by @_ and, if three separate arrays are passed, @_ will contain all 3 of them (27 scalar variables) and you can't separate them by index @_[0], etc, since the input to your subroutine is, in effect, one large array, rather than a collection of 3 smaller arrays. In effect, and in reality, your subroutine would put all of the members of all of the 3 arrays into @array1.

Hopefully, I'm not drifting too far off of the reservation, here, as I fear I'm wandering into the land of overly convoluted explanation again ;) The advantage to you, the programmer, in this instance, would be that you could use Perl references to pass scalar references to each array to your subroutine. As difficult as it would be to manage the above three arrays using straight passing to your subroutine (you would have to determine their size before passing them in and then keep track of that by passing even more information, not to mention re-allocating those members back into the subroutine's local arrays), it would be a bit easier to pass your subroutine three references to your three arrays, like so:

mynewsubroutine(\@array1, \@array2, \@array3);

Now, the reason this makes life easier for you is that you're only passing your subroutine 3 scalar variables, rather than an indeterminate amount of any other kind. Inside the subroutine, you can easily work with the variables using the dereferencing techniques we went over in our understanding Perl references post. For instance, you could do "foreach" on all 3 arrays separately, and process the internal array variables that way, effectively making the size of any of those arrays inconsequential (less work for you), like so:

my $array1 = shift;
foreach $thingy (@{$array1}) {
print "Thingy $thingy\n";
}


I'm oversimplifying to a certain degree, but this is getting out of hand just swimmingly in spite of my best efforts ;)

3. Although I promised I wouldn't go here, I must (but I'll keep it theoretical so we can dispense with it post-haste). If you ever do any super-complex programming, like building matrices, doing crazy manipulation of filehandles (remember that "any" Perl data type can be referenced) or things along the nature of manipulating arrays of hashes of multiple nested arrays of hashes, using references can make it a lot simpler for you to keep your head from exploding (which is a lousy way to end the day ;)

Hopefully, these answers have been somewhat helpful, and/or illustrative regarding the question at hand (why use references at all, and are they even really necessary?) If you're interested in reading more on the subject, check out Chapter 18 of bjnet.edu.cn's introduction to Perl. It's written very well and is probably simpler to follow than my meandering over-explanations ;) Plus, all the other chapters are available online, so you could download them all and have yourself a very nice free Perl reference in however long it takes you to download the HTML.

Cheers to all, and thank you for your response to the post that spawned this one. There's nothing quite so rewarding as knowing that I'm actually writing something at least a few people are really interested in reading :)

, Mike




Discover the ClickBank affiliate program that pays 100% commission!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.