Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > weird behavior when passing hashes to subroutine

Reply
Thread Tools

weird behavior when passing hashes to subroutine

 
 
Patrick Hartman
Guest
Posts: n/a
 
      02-19-2010
Hi all, I was working on a program today and made a sub routine that I
was passing a few scalars and also a hash to as arguments. This is
what I initially tried:

my %foo = qw(pepsi cola doctor pepper seven up);
my $bar = 'soda is yummy!';

&drink(%foo,$bar);

sub drink {
my (%sodas,$opinion) = @_;

# do whatever here
print "yummy!";
}

The result was not what I was expecting. The $bar value that I was
expecting to be the $opinion scalar ended up as a extra key in the
%sodas hash as undef, and $opinion was empty. I played around a little
and found that if I reverse the order so the scalar is passed before
the hash, it worked like I was hoping:

my %foo = qw(pepsi cola doctor pepper seven up);
my $bar = 'soda is yummy!';

&drink($bar,%foo);

sub drink {
my ($opinion,%sodas) = @_;

# do whatever here
print "yummy!";
}

Is there a rule as to what order to pass types to a subroutine? I'm a
little confused on this one. Thanks,

Patrick
 
Reply With Quote
 
 
 
 
sln@netherlands.com
Guest
Posts: n/a
 
      02-19-2010
On Thu, 18 Feb 2010 16:43:38 -0800 (PST), Patrick Hartman <(E-Mail Removed)> wrote:

[snip]

>Is there a rule as to what order to pass types to a subroutine? I'm a
>little confused on this one. Thanks,
>
>Patrick


There is no rules in Perl, just syntax. If it doesen't work like
you expect, Perl has no way of knowing, and thinks that's what you intend.
Use strict/warnings to help you out.

Basically, I think this is what you did:

my %sodas = (
# The never ending list
'pepsi',
'cola',
'doctor',
'pepper',
'seven',
'up',
'soda is yummy!',
# Add to the never ending list
);

And, you should have gotten an "Odd number of elements ..."
type of message.

If your looking for a "I before E, except after C"
rhyme, I can't think of any.

Also, you probably don't need ampersand before the function
call.

-sln
 
Reply With Quote
 
 
 
 
John Bokma
Guest
Posts: n/a
 
      02-19-2010
Patrick Hartman <(E-Mail Removed)> writes:

> Hi all, I was working on a program today and made a sub routine that I
> was passing a few scalars and also a hash to as arguments. This is
> what I initially tried:
>
> my %foo = qw(pepsi cola doctor pepper seven up);
> my $bar = 'soda is yummy!';
>
> &drink(%foo,$bar);
>
> sub drink {
> my (%sodas,$opinion) = @_;
>
> # do whatever here
> print "yummy!";
> }
>
> The result was not what I was expecting. The $bar value that I was
> expecting to be the $opinion scalar ended up as a extra key in the
> %sodas hash as undef, and $opinion was empty. I played around a little
> and found that if I reverse the order so the scalar is passed before
> the hash, it worked like I was hoping:
>
> my %foo = qw(pepsi cola doctor pepper seven up);
> my $bar = 'soda is yummy!';
>
> &drink($bar,%foo);
>
> sub drink {
> my ($opinion,%sodas) = @_;
>
> # do whatever here
> print "yummy!";
> }
>
> Is there a rule as to what order to pass types to a subroutine? I'm a
> little confused on this one. Thanks,


You have to be aware that the hash eats up @_ (it's the same if you use
an array, i.e. my ( @foo, $bar ) = @_; will result in all of @_ ending
up in @foo).

You could do:

sub drink {
my $opinion = pop @_;
my %sodas = @_;
:
:
}

pop removes the last item from @_ (in this case) and assigns it to
$opionion.

You can also decide to pass a reference to your hash instead, see

perldoc perlreftut

--
John Bokma j3b

Hacking & Hiking in Mexico - http://johnbokma.com/
http://castleamber.com/ - Perl & Python Development
 
Reply With Quote
 
sln@netherlands.com
Guest
Posts: n/a
 
      02-19-2010
On Thu, 18 Feb 2010 20:21:32 -0600, Don Piven <(E-Mail Removed)> wrote:

>(E-Mail Removed) wrote:
>> On Thu, 18 Feb 2010 16:43:38 -0800 (PST), Patrick Hartman <(E-Mail Removed)> wrote:
>>
>> [snip]
>>
>>> Is there a rule as to what order to pass types to a subroutine? I'm a
>>> little confused on this one. Thanks,
>>>
>>> Patrick

>>
>> There is no rules in Perl, just syntax. If it doesen't work like
>> you expect, Perl has no way of knowing, and thinks that's what you intend.
>> Use strict/warnings to help you out.
>>
>> Basically, I think this is what you did:
>>
>> my %sodas = (
>> # The never ending list
>> 'pepsi',
>> 'cola',
>> 'doctor',
>> 'pepper',
>> 'seven',
>> 'up',
>> 'soda is yummy!',
>> # Add to the never ending list
>> );

>
>Well, it would have been more like
>
>drink(qw(pepsi cola doctor pepper seven up), 'soda is yummy').
>
>That's seven arguments. Now when you do
>
>my (%sodas, $opinion) = @_ ;
>
>the %sodas hash is going to suck up all the items in the argument list,
>and leave nothing for $opinion, so 1) $opinion is going to be undef, and
>2) the last argument is treated as a key, and since there are no more
>elements, that key gets a value of undef.
>
>Reversing the order of arguments ($opinion, %sodas) works because
>$opinion gets the first element of the list, and %sodas sucks down the
>rest of 'em in key/value order.
>
>> And, you should have gotten an "Odd number of elements ..."
>> type of message.

>
>That's a compile-time error, since the compiler has to know how many
>elements are in the initializer in order to know if it's an odd number.
> The compiler won't see a problem with %hash = @_ since it has no clue
>how long @_ is going to be.
>
>Don


Thanks, next time I won't do that (or do it a different way).

-sln
 
Reply With Quote
 
Jürgen Exner
Guest
Posts: n/a
 
      02-19-2010
Patrick Hartman <(E-Mail Removed)> wrote:
>Hi all, I was working on a program today and made a sub routine that I
>was passing a few scalars and also a hash to as arguments. This is
>what I initially tried:
>
>my %foo = qw(pepsi cola doctor pepper seven up);
>my $bar = 'soda is yummy!';
>
>&drink(%foo,$bar);
>
>sub drink {
> my (%sodas,$opinion) = @_;
>
> # do whatever here
> print "yummy!";
>}
>
>The result was not what I was expecting. The $bar value that I was
>expecting to be the $opinion scalar ended up as a extra key in the
>%sodas hash as undef, and $opinion was empty.


From "perldoc perlsub':
The Perl model for function call and return values is simple: all
functions are passed as parameters one single flat list of scalars,

Therefore at the point where you are doing
my (%sodas,$opinion) = @_;
there is no recollection that those values in @_ where once organized
into two distinct variables. And of ourse %s is grabbing as many as it
can.

>sub drink {
> my ($opinion,%sodas) = @_;


In this case $opinion will grab the first value (it can't grab any
others bedause its a scalar) and thus leaving the rest of the list for
%sodas.

>Is there a rule as to what order to pass types to a subroutine? I'm a
>little confused on this one.


That question is not really targeting the root issue. But as a rule of
thumb if you want to extract arguments like that then they have to have
a known lenght, i.e. be scalars or hashes or arrays of a known, fixed
length.
Then on top of that you can also get away with one single hash or array
of random length at the very end of the argument list. This is the case
in your second example.

If you have more than one of those list-like arguments with an arbitrary
number of elements then you have to pass references instead or resort to
awkward workarounds like e.g. passing the number of elements as an
additional argument.

jue
 
Reply With Quote
 
sreservoir
Guest
Posts: n/a
 
      02-19-2010
On 2/18/2010 9:21 PM, Don Piven wrote:
> http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
>> On Thu, 18 Feb 2010 16:43:38 -0800 (PST), Patrick Hartman
>> <(E-Mail Removed)> wrote:
>>
>> [snip]
>>
>>> Is there a rule as to what order to pass types to a subroutine? I'm a
>>> little confused on this one. Thanks,
>>>
>>> Patrick

>>
>> There is no rules in Perl, just syntax. If it doesen't work like
>> you expect, Perl has no way of knowing, and thinks that's what you
>> intend.
>> Use strict/warnings to help you out.
>>
>> Basically, I think this is what you did:
>>
>> my %sodas = (
>> # The never ending list
>> 'pepsi',
>> 'cola',
>> 'doctor',
>> 'pepper',
>> 'seven',
>> 'up',
>> 'soda is yummy!',
>> # Add to the never ending list
>> );

>
> Well, it would have been more like
>
> drink(qw(pepsi cola doctor pepper seven up), 'soda is yummy').
>
> That's seven arguments. Now when you do
>
> my (%sodas, $opinion) = @_ ;
>
> the %sodas hash is going to suck up all the items in the argument list,
> and leave nothing for $opinion, so 1) $opinion is going to be undef, and
> 2) the last argument is treated as a key, and since there are no more
> elements, that key gets a value of undef.
>
> Reversing the order of arguments ($opinion, %sodas) works because
> $opinion gets the first element of the list, and %sodas sucks down the
> rest of 'em in key/value order.
>
>> And, you should have gotten an "Odd number of elements ..."
>> type of message.

>
> That's a compile-time error, since the compiler has to know how many
> elements are in the initializer in order to know if it's an odd number.
> The compiler won't see a problem with %hash = @_ since it has no clue
> how long @_ is going to be.


no. it is not.

perl -We 'sub a { %_ = @_ } a(0)' -> warning
perl -e 'sub a { %_ = @_ } a(0)' -> nothing

--

"Six by nine. Forty two."
"That's it. That's all there is."
"I always thought something was fundamentally wrong with the universe"
 
Reply With Quote
 
Uri Guttman
Guest
Posts: n/a
 
      02-19-2010
>>>>> "PH" == Patrick Hartman <(E-Mail Removed)> writes:

PH> Hi all, I was working on a program today and made a sub routine that I
PH> was passing a few scalars and also a hash to as arguments. This is
PH> what I initially tried:

PH> my %foo = qw(pepsi cola doctor pepper seven up);
PH> my $bar = 'soda is yummy!';

PH> &drink(%foo,$bar);

read perldoc perlsub. that isn't doing what you think it does.

PH> sub drink {
PH> my (%sodas,$opinion) = @_;

actually that is the bad line. the hash will slurp in all of @_ (and
should give you an odd count warning IF you used warnings which you
should do). nothing will ever be assigned to $opinion.

PH> The result was not what I was expecting. The $bar value that I was
PH> expecting to be the $opinion scalar ended up as a extra key in the
PH> %sodas hash as undef, and $opinion was empty. I played around a little
PH> and found that if I reverse the order so the scalar is passed before
PH> the hash, it worked like I was hoping:

PH> my %foo = qw(pepsi cola doctor pepper seven up);
PH> my $bar = 'soda is yummy!';

PH> &drink($bar,%foo);

PH> sub drink {
PH> my ($opinion,%sodas) = @_;

PH> # do whatever here
PH> print "yummy!";
PH> }

PH> Is there a rule as to what order to pass types to a subroutine? I'm a
PH> little confused on this one. Thanks,

no rule about order. just you the first array or hash in the left side
of any assignment gets all the rest of the values from the right
side. so if you must have one, it should be the last thing on the left
side. or use references to pass multiple aggregates around.

uri

--
Uri Guttman ------ (E-Mail Removed) -------- http://www.sysarch.com --
----- Perl Code Review , Architecture, Development, Training, Support ------
--------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
 
Reply With Quote
 
Patrick Hartman
Guest
Posts: n/a
 
      02-19-2010
On Feb 18, 8:11*pm, John Bokma <(E-Mail Removed)> wrote:
> You have to be aware that the hash eats up @_ (it's the same if you use
> an array, i.e. my ( @foo, $bar ) = @_; will result in all of @_ ending
> up in @foo).



Thanks John, that explanation made the most sense. I was unaware that
using a hash or array gobbled up all the @_ contents, this behavior
makes sense now I know that.

Thanks everyone else for the input and suggestions. Hash references
are still foreign to me (I have seen them but don't really understand
them). I am still working through the end of the Llama book, but I
have the Alpaca book waiting on my desk for when I am done. I know it
covers references so hoping that will give me some clarity.

I am still in the beginning of the learning process, so I appreciate
all the help on here.

Patrick
 
Reply With Quote
 
Justin C
Guest
Posts: n/a
 
      02-19-2010
On 2010-02-19, Patrick Hartman <(E-Mail Removed)> wrote:
> Hi all, I was working on a program today and made a sub routine that I
> was passing a few scalars and also a hash to as arguments. This is
> what I initially tried:
>
> my %foo = qw(pepsi cola doctor pepper seven up);
> my $bar = 'soda is yummy!';
>
> &drink(%foo,$bar);


see 'Pass by Reference' in perdoc perlsub

The scalar isn't a problem, it's the hash so I'd do:

&drink(\%foo, $bar); # passes a reference to the hash, not the hash

(someone will probably come along in a minute and tell you that you
shouldn't be using the & calling your subs unless you know why you need
to. I still don't understand this so I keep out of those discussions and
never use the & anyway).
>
> sub drink {

my ($foo, $bar) = @_;
> my (%sodas,$opinion) = @_;
>
> # do whatever here

dereference the hashref here (it's all in perlsub)
> print "yummy!";
> }
>
> The result was not what I was expecting. The $bar value that I was
> expecting to be the $opinion scalar ended up as a extra key in the
> %sodas hash as undef, and $opinion was empty. I played around a little
> and found that if I reverse the order so the scalar is passed before
> the hash, it worked like I was hoping:
>
> my %foo = qw(pepsi cola doctor pepper seven up);
> my $bar = 'soda is yummy!';
>
> &drink($bar,%foo);
>
> sub drink {
> my ($opinion,%sodas) = @_;
>
> # do whatever here
> print "yummy!";
> }
>
> Is there a rule as to what order to pass types to a subroutine? I'm a
> little confused on this one. Thanks,
>
> Patrick



Justin.

--
Justin C, by the sea.
 
Reply With Quote
 
Jens Thoms Toerring
Guest
Posts: n/a
 
      02-19-2010
Justin C <(E-Mail Removed)> wrote:
> On 2010-02-19, Patrick Hartman <(E-Mail Removed)> wrote:
> > Hi all, I was working on a program today and made a sub routine that I
> > was passing a few scalars and also a hash to as arguments. This is
> > what I initially tried:
> >
> > my %foo = qw(pepsi cola doctor pepper seven up);
> > my $bar = 'soda is yummy!';
> >
> > &drink(%foo,$bar);


> see 'Pass by Reference' in perdoc perlsub


> The scalar isn't a problem, it's the hash so I'd do:


> &drink(\%foo, $bar); # passes a reference to the hash, not the hash


But there's one important difference that the OP should keep in
mind: The original call

drink(%foo,$bar);

passes copies of the hash keys and values to the subroutine, thus
any changes done to them are local to that subroutine and don't
change anything about the original hash. But when one passes a hash
by reference then what the function receives is just a pointer to
that hash and thus all changes done to the hash via the reference
are done to the original hash in the calling function. So, if the
hash isn't changed in the function then passing a reference is fine
(and probably faster since the elements don't have to be copied),
but if that's not the case then passing a hash reference instead of
a list of its elements may lead to unexpected effects, i.e. the
%foo' hash suddenly being changed after a call of drink(). To
avoid that a copy of the original hash would have to be made and
a reference to that copy be passed to the function.

Regards, Jens
--
\ Jens Thoms Toerring ___ (E-Mail Removed)
\__________________________ http://toerring.de
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
use one subroutine's variable value in another subroutine inside a module. king Perl Misc 5 04-29-2007 06:39 AM
using hashes as keys in hashes Steven Arnold Ruby 3 11-23-2005 03:25 PM
Hash of hashes, of hashes, of arrays of hashes Tim O'Donovan Perl Misc 5 10-28-2005 05:59 AM
Cant return multiple hashes from subroutine sam Perl Misc 3 01-06-2005 04:46 PM
Hashes of Hashes via subs Ben Holness Perl 8 10-08-2003 06:57 AM



Advertisments