Andrew Gaffney wrote:
I'm not exactly a beginner. I've been using Perl for about 8 months. It's just that I've never written a subroutine where I need to pass array or hash *references*.
Regardless of how long you have been writing in Perl, if you have not yet: Started using strict and warnings in every script Taken time to get comfortable with references and their use as argument to function Then you are still a beginner.
Prototypes are for very well-established functions that have taken on library status. There they can help support a more streamlined coding style. Don't use them at this point in your learning efforts.
: Now, how do I get those values in the subroutine? : : sub my_subroutine([EMAIL PROTECTED]@) { : my ($scalar1, $scalar2, $arrayref1, $arrayref2) = @_; : }
That's about it. Though I might suggest a style change.
- Use a variable names that describe the data, not it's structure.
- Separate words in variables with underscores.
I do in real code. The above is just sample code.
- Use comments and white space that aids the maintainer.
- Don't use prototypes.
sub sales_by_quarter { my( $first_quarter_name, # scalar $second_quarter_name, # scalar $first_quarter_data, # array reference $second_quarter_data, # array reference ) = @_; # ... }
sub sales_comparison_by_quarter {
# These are references to arrays. # Any changes you make *will* affect the original data. # Think of them as read only. my( $Q1_data, # array reference $Q2_data, # array reference ) = @_;
# Region names will default if not provided my $Q1_region = shift || 'Region 1'; my $Q2_region = shift || 'Region 2';
# ... }
: Another thing, how do you access an array through a reference? : I know you access a hash through a reference by doing : '$hashref->{hashkey}' instead of just '$hashref{hashkey}', but : I've never done it with arrays (never needed to).
The arrow operator (->) is used to dereference references. Read perlref and perl reftut.
$second_quarter_data->[ $month ]
: One more thing (I promise). Do I need to do anything special to : pass arrays as references to the function, like this: : : my_subroutine $scalar1, $scalar2, [EMAIL PROTECTED], [EMAIL PROTECTED]; : : or can I pass them without the '\'? Sorry for all the : questions in one post, but at least they are all related :)
Yes, but you have already answered this at the beginning of your message:
: I'm trying to write a subroutine that takes two scalars : and two arrays as parameters. I've read that if you try : to do this in a function, both arrays will get combined : within '@_'.
I don't understand how that explains how I can pass the array and hash *references* to my function. If I use prototypes, this is taken care of for me.
Don't count on that.
If I don't use prototypes,
Bad distinction. Just put the prototypes on the shelf, please, and stick to learning Perl.
do I need the '\' in front of arrays and hashes in the function call?
If the array was declared statically, one way to offer a reference to it is indeed to offer the reference directly in the parameter list. You could also assign a reference to a scalar, and offer that scalar as an argument.
my @clunky_stay_at_home_array = qw /yada yada sis boom bah/; do_spectacular_things with([EMAIL PROTECTED]); my $sleek_array_keycard = [EMAIL PROTECTED]; visit_wondrous_faraway_places( $sleek_array_keycard);
What about anonymous hashes?
Lets not jump to anonymous hashes specifically right now. how about anonymous structures in general? I seldom use statically declared arrays or hashes myself, unless they are scope to a very short, throwaway lifetime. Anonymous structures are already packed for travel:
my $sleek_array_keycard = [qw /yada yada sis boom bah/]; visit_wondrous_faraway_places( $sleek_array_keycard);
my_subroutine $scalar1, $scalar2, {param1 => 'value1', param2 => 'value2'}, $arrayref;
In the above, wouldn't the hash just get squashed into @_? Wouldn't my @_ end up as the following within the function?
Nope. The syntax above could also be written:
my $blandly_named_hash_ref = {param1 => 'value1', param2 => 'value2'}; because the braces act as operators returning a reference to the aqnonymous hash, just as brackets do for an anonymous array. That reference is a scalar, which cannot be flattened, as it is already atomic.
my_subroutine $scalar1, $scalar2, $blandly_named_hash_ref, $arrayref;
OTOH, if you offered a hash, rather than a reference to a hash my %blandly_named_hash = (param1 => 'value1', param2 => 'value2'); my_subroutine $scalar1, $scalar2, %blandly_named_hash, $arrayref;
or
my_subroutine $scalar1, $scalar2, (param1 => 'value1', param2 => 'value2'), $arrayref;
The hash contents would be flattened in the list.
A reference is a scalar. Scalars are atomic--they do not get flattened passing through parameter or return list, or being stored within other structures. This is why refererences provide the basis for power programming.
I'm getting conflicting advice between your post and another post to this thread. Maybe if I post my code, you can recommend the best way for me to setup my functions and the calls to them (and whether to prototype them). This code will be for an Apache 1.3.x/mod_perl 1.x/Mason website.
I am writing a module that contains functions that I commonly use in my scripts. I have written a lot of scripts that generate HTML reports from the data in the MySQL DB. My boss wants these reports to spit out their data either in HTML or Excel. I had the idea of writing functions that take a series of scalars and arrays that describe the data to be in the report.
The functions (generate_report_html() and generate_report_excel()) actually process the arrays and such and generate the reports in HTML or Excel. This makes it easier to create new reports and greatly cuts down on code duplication. Here are my functions (keep in mind I only started writing them at 1AM and they aren't near finished):
<code> package Skyline;
<big SNIP of other module code>
sub generate_report_html([EMAIL PROTECTED]@) { my ($title, $columns, $data) = @_; print <<' EOF'; <html> <body> <center><img src='/original_logo_60pc.jpg'><p> <h2>$title Report</h2></center> <p> <table width=100%> <tr> EOF foreach (@$columns) { print "<td><b><u>$_</u></b></td>"; } print "</tr>\n"; foreach my $row (@$data) { print "<tr>"; foreach (@$row) { print "<td>$_</td>"; } print "</tr>\n"; } print <<' EOF'; </table> </body> </html> EOF }
sub generate_report_excel([EMAIL PROTECTED]@) { my ($title, $columns, $data) = @_; # No other code written for this function yet } </code>
A typical script that generates a report using these functions would look like:
<code> use Skyline; use CGI;
my $cgi = new CGI; my @data; my $dbh = init_db(); # Module function to connect to MySQL DB using DBI my $sth = $dbh->prepare("SELECT fname, lname, homephone FROM people ORDER BY lname"); $sth->execute; my $ref; while($ref = $sth->fetchrow_hashref) { push @data, ["$ref->{lname}, $ref->{fname}", "$ref->{homephone}"]; }
my @columns = ("Name", "Phone Number"); generate_report_html("Customers", @columns, @data); </code>
This then generates a nice formatted HTML report with minimal code. What would you change (if anything) about the above code (module or report scripts)?
-- Andrew Gaffney Network Administrator Skyline Aeronautics, LLC. 636-357-1548
-- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>