http://www.perlmonks.org?node_id=594377

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

Lo, Given that:
$self->client->param( 'usr_id' ) returns 1 $self->client->param( 'edit_usr_id' ) returns undef, or something $self->client->param( 'mode' ) returns 'add'
How come the below really screws up the hash:
$self->log(LOGDEBUG, 'EDIT_USER: '. Dumper( { state => 'db_user', usr_id => $self->client->param( 'usr_id' ), edit_usr_id => $self->client->param( 'edit_usr_id' ), mode => $self->client->param( 'mode' ) })); EDIT_USER: $VAR1 = { 'add' => undef, 'usr_id' => '1', 'edit_usr_id' => 'mode', 'state' => 'db_user' };
And yet doing it this way is as expected:
my $a = $self->client->param( 'edit_usr_id' ); $self->log(LOGDEBUG, 'EDIT_USER: '. Dumper( { state => 'db_user', usr_id => $self->client->param( 'usr_id' ), edit_usr_id => $a, mode => $self->client->param( 'mode' ) })); EDIT_USER: $VAR1 = { 'usr_id' => '1', 'mode' => 'add', 'edit_usr_id' => undef, 'state' => 'db_user' };

Replies are listed 'Best First'.
Re: mysterious hash ref result
by BrowserUk (Patriarch) on Jan 12, 2007 at 13:44 UTC

    In a word, context. Try it like this:

    $self->log(LOGDEBUG, 'EDIT_USER: '. Dumper( { state => 'db_user', usr_id => $self->client->param( 'usr_id' ), edit_usr_id => scalar( $self->client->param( 'edit_usr_id' ) ) +, mode => $self->client->param( 'mode' ) } ) );

    Assuming that produces the desired result, the problem is that in your first example, you are calling $self->client->param( 'edit_usr_id' ) in a list context, whereas in your second example it is called in a scalar context.

    self->client->param( .. ) probably finishes something like:

    sub param { ... return unless exists ... return ...; }

    That is to say, it executes a bare return statement if the parameter does not exist. In a scalar context, a bare return will assign undef to the scalar (lvalue). In a list context, it will return the 'empty list' (usually denoted by ()), but when an empty list is incorporated into a larger list, it is folded to nothing. Essentially, it disappears. Eg:

    Perl> sub x{ return };; Perl> @b = ( 1,2,'a', x(), 5, 6 );; Perl> print "@b";; 1 2 a 5 6 Perl> @b = ( 1,2,'a', scalar( x() ), 5, 6 );; Perl> print "@b";; Use of uninitialized value in join or string at (eval 13) line 1 1 2 a 5 6

    In the former, sub x() is called in a list context, so the return statement returns the empty list and that get folded and disappears making no contribution to the state of @b.

    In the latter, it is called in a scalar context, so it returns undef, which causes the 4th element of @b to take the value undef.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Ah, thank you all very much for that. I did not know that being on the RHS of a => meant list context. I've tracked down the method and indeed it does return a list or scalar, depending upon context.
        I did not know that being on the RHS of a => meant list context

        To be precise, it doesn't really. Being on the inside of an anonymous hash constructor means list context.

Re: mysterious hash ref result
by Util (Priest) on Jan 12, 2007 at 14:00 UTC
    Perhaps param() is using a bare return on error. A bare return returns undef or the empty list, depending on the context in which the subroutine was called! Your second example calls param() in scalar context, so a bare return would give you undef; Your first example calls param() in list context, so a bare return would give you (). To help confirm my diagnosis, try replacing your anon-hash constructors {...} with anon-array constructors [...], and impose scalar context by using scalar directly. By avoiding the hash, you will prevent confusion from the random hash ordering in your dump.
    use strict; use warnings; ... my $dump_string = Dumper [ ### Uncomment one or the other of these two lines. # edit_usr_id => $self->client->param( 'edit_usr_id' ), edit_usr_id => scalar( $self->client->param( 'edit_usr_id' ) ), mode => $self->client->param( 'mode' ) ]; $self->log(LOGDEBUG, 'EDIT_USER: '.$dump_string ));
    It should give something like:
    EDIT_USER: $VAR1 = [ 'edit_usr_id', undef, 'mode', 'add', ];
    or:
    EDIT_USER: $VAR1 = [ 'edit_usr_id', 'mode', 'add', ];
    Also, you should have gotten a warning about 'Odd number of elements' in your hash assignment in your first example. You do have warnings turned on, don't you?
Re: mysterious hash ref result
by ferreira (Chaplain) on Jan 12, 2007 at 13:48 UTC

    I could not write an example that reproduced this exact behavior, but in the construction:

    { state => 'db_user', usr_id => $self->client->param( 'usr_id' ), edit_usr_id => $self->client->param( 'edit_usr_id' ), mode => $self->client->param( 'mode' ) }
    the methods are called in list context, and they may mess with the result if they do not return a list with an odd number of elements. For example,
    $ perl -MData::Dump=dump -e ' sub f { (1, 2) }; print dump({ a => f, b => 1 }) '
    prints
    { 1 => undef, 2 => "b", a => 1 }

    As I told, I could not get the same behavior returning an empty list, but I am still investigating. Maybe if you omitted parts in your explanation, this case fits.

Re: mysterious hash ref result
by Anonymous Monk on Jan 12, 2007 at 13:45 UTC
    Consider the following
    use Data::Dumper; sub nothing { return () } my %hash = ( state => 'db_user', usr_id => 1, edit_usr_id => nothing(), mode => 'add', ); warn Dumper\%hash; %hash = ( state => 'db_user', usr_id => 1, edit_usr_id => scalar nothing(), mode => 'add', ); warn Dumper\%hash; __DATA__ $VAR1 = { 'add' => undef, 'usr_id' => 1, 'edit_usr_id' => 'mode', 'state' => 'db_user' }; $VAR1 = { 'usr_id' => 1, 'mode' => 'add', 'edit_usr_id' => undef, 'state' => 'db_user' };
Re: mysterious hash ref result
by Herkum (Parson) on Jan 12, 2007 at 13:31 UTC

    One thing you should not be doing is using $a, that is a special variable that Perl uses. As for the rest of it, there is not enough information for me to understand what is going on for me to help debug it.