Web Developer's Virtual Library: Encyclopedia of Web Design Tutorials, Articles and Discussions


WDVL Newsletter

Active Server Pages
JSP/Java Servlets
Microsoft SQL Server
Daily Backup
Dedicated Servers
Streaming Audio/Video
24-hour Support    

jobs.webdeveloper.com

Hiermenus


e-commerce
Partner With Us















Developer Channel
FlashKit.com
JavaScript.com
JavaScriptSource
Developer Jobs
ScriptSearch
StreamingMediaWorld
Web Developer's Journal
Web Developer's Virtual Library
WebDeveloper.com
Webreference
Web Hosts
XMLfiles.com

internet.com
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers


Passing Lists and Hashes - Page 10

July 13, 2001

We mentioned earlier, when we started on the subject of passed arguments, that passing lists and hashes directly into a subroutine causes list flattening to occur, just as it does with ordinary list definitions. Consequently, if we want to pass an array or hash to a subroutine, and keep it intact and separate from the other arguments, we need to take additional steps. Consider the following snippet of code:

$message = "Testing";
@count = (1, 2, 3);
testing ($message, @count);
# calls 'testing' -- see below

The array @count is flattened with $message in the @_ array created as a result of this subroutine, so as far as the subroutine is concerned the following call is actually identical:

testing ("Testing", 1, 2, 3);

In many cases this is exactly what we need. To read the subroutine parameters we can just extract the first scalar variable as the message and put everything else into the count:

sub testing {
  ($message, @count) = @_;
...
}

Or, using shift:

sub testing {
  $message = shift;
  # now we can use @_  directly in place of @count
...
}

The same principle works for hashes, which as far as the subroutine is concerned are just more values. It is up to the subroutine to pick up the contents of @_ and convert them back into a hash:

sub testing {
  ($message, %count) = @_;
  print "@_";
}

testing ("Magpies", 1 => "for sorrow",
 2 => "for joy", 3 => "for health", 4 =>
"for wealth", 5 => "for sickness",
 6 => "for death");

However, this only works because the last parameter we extract inside the subroutine absorbs all the remaining passed parameters. If we were to write the subroutine to pass the list first and then the scalar afterwards, all the parameters are absorbed into the list and the scalar is left undefined:

sub testing {
  (@count, $message) = @_; # ERROR
  print "@_";
}

testing(1, 2, 3, "Testing");
# results in @count = (1, 2, 3, "Testing")
#and $message = undef

If we can define all our subroutines like this we won't have anything to worry about, but if we want to pass more than one list we still have a problem.

If we attempt to pass both lists as-is, then extract them inside the subroutine, we end up with both lists in the first and the second left undefined:

sub testing {
  my (@messages, @count) = @_; # wrong!
  print "@_";
}

@msgs = ("Testing", "Testing");
@count = (1, 2, 3);
testing(@msgs, @count);
# results in @messages = ("Testing",
#"Testing", "Testing", 1, 2, 3) and @count = ();

The correct way to pass lists and hashes, and keep them intact and separate, is to pass references. Since a reference is a scalar, it is not flattened like the original value and so our data remains intact in the form that we originally supplied it:

testing (["Testing", "Testing"], [1, 2, 3]);
  # with two lists
testing (\@messages, \@count);
  # with two array variables
testing ($aref1, $aref2);
  # with two list references

Inside the subroutine we then extract the two list references into scalar variables and dereference them using either @{$aref} or $aref->[index] to access the list values:

sub testing {
  ($messages, $count) = @_;
  # print the testing messages
    foreach (@ {$messages}) {
    print "$_  ... ";
  }
  print "\n";
  # print the count;
  foreach (@ {$count}) {
    print "$_! \n";
  }
}

Another benefit of this technique is efficiency; it is better to pass two scalar variables (the references) than it is to pass the original lists. The lists may contain values that are large both in size and number. Since Perl must store a local copy of the @_ array for every new subroutine call in the calling stack, passing references instead of large lists can save Perl a lot of time and memory.

Passing Parameters - Page 9
Professional Perl Programming
Converting Scalar Subroutines into List Processors - Page 11


Up to => Home / Authoring / Languages / Perl / ProPerl




Jupiter Online Media: internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and Jupiter Online Media

Jupitermedia Corporate Info


Legal Notices, Licensing, & Permissions, Privacy Policy.

Web Hosting | Newsletters | Tech Jobs | Shopping | E-mail Offers