jktstance has asked for the wisdom of the Perl Monks concerning the following question:

I'm reading through the 3rd part of the beginner's tutorial (http://news.oreilly.com/2008/06/a-beginners-introduction-to-pe.html) and I have a "what if" question. Towards the bottom, there is a piece of code you can look at that parses and summarizes an http log file. One of the functions in it is:
sub report_section { my ( $header, %types ) = @_; say $header; for my $type ( sort keys %types ) { say "$type: $types{$type}"; } }
I'm confused about data types here. Isn't the @_ variable an array? If so, then is the %types hash converted to a flat list or string when passed?

Now, what if I wanted to reference the @_ variable directly, instead of reassigning its parts to variables as is done here. Obviously to print the header, I just write say $_[0];, but how do I handle a passed hash?

I think the answer here is to use references, but I haven't learned much about them yet and I'm wondering if there's a way to do this without them.

EDIT: Some more testing shows me that @_ is a flattened list. @_1 .. $#_ should give me an array that is the %types hash. I tried to substitute sort keys @_[1 .. $#_] instead of sort keys %types, but since I'm only running Perl version 5.8, the keys function does not work. How wrong am I?

Replies are listed 'Best First'.
Re: Passing a scalar and hash as subroutine arguments
by AnomalousMonk (Archbishop) on Jan 24, 2014 at 22:21 UTC

    Try  sort keys %{ { @_[ 1 .. $#_ ] } }
    (Update: On second thought, don't, because there's no benefit to doing it that way – although it should work in your particular case.)

Re: Passing a scalar and hash as subroutine arguments
by Laurent_R (Canon) on Jan 25, 2014 at 18:48 UTC
    This a quick demonstration of what is going on under the Perl debugger:
    DB<1> @c = ('jan', 1, 'feb', 2, 'mar', 3); DB<2> x \@c 0 ARRAY(0x80359de8) 0 'jan' 1 1 2 'feb' 3 2 4 'mar' 5 3
    So, @c is an array.
    DB<3> %d = @c; DB<4> x \%d 0 HASH(0x8042f6d8) 'feb' => 2 'jan' => 1 'mar' => 3
    Copying @c into %d sorts of promote the data structure into a hash (provided the number of elements is even). This is what happens in your code snippet. The @_ array contains just a flattened list. $header take the first element of @_, and the rest of @_ is copied into the %types hash.
Re: Passing a scalar and hash as subroutine arguments
by Anonymous Monk on Jan 25, 2014 at 01:07 UTC

    How wrong am I?

    Grab a copy of the free book Modern Perl , it explains that yes , everything does flatten into @_ , its an array of scalars ( "aliases" )

      Yes - everything does get 'squashed'. Internally, an array and a hash are much the same - it's just a hash is an array with an even number of paired values. So you can coerce from hash to array and back again. That's what's happening here.

      Probably the easiest way of handling passing a whole hash into a subroutine is by reference. E.g. invoke your sub with:

      my_sub ( $value, \%myhash );

      And within the sub:

      my ( $value, $hashref ) = @_; foreach my $key ( keys %$hashref ) { print "$key = $$hashref{'$key'}\n"; }

      Although you should note that a has passed by reference - if you modify it within the sub, it'll modify the 'source instance'. Read 'perlref' for more detail.