Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Dereferencing in blessed object

by Bod (Curate)
on Feb 25, 2021 at 22:58 UTC ( #11128808=perlquestion: print w/replies, xml ) Need Help??

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

I have a bit of a strange problem... I have consulted the very useful assistance haukex and others provided on Re^9: Preparing data for Template.

The problem is dereferencing an entry in a hash. At first, I thought it was the trouble I always seem to run into when using references. So, I built some test code to check what I was doing and it works as expected.

use strict; my $val = 'A'; my $vars = { 'test' => $val }; reftest('testing', $vars); sub reftest { my ($value, %vars) = @_; print "$value\n"; print $$vars{'test'}."\n"; } C:\Users\ian\Perl>perl dereference.pl testing A
The output is exactly as expected.

But the code on the webserver is structured the same. The only difference is that the subroutine is a method in a blessed object...could this really make a difference?

The calling code...

my $vars = { 'testpage' => $data{'testpage'} }; $html->process('index', $vars);

And the method within the $html object...

sub process { my ($self, $disp, %v) = @_; my $testpage = $$v{'testpage'}; print "<h1>".$testpage."</h1>\n"; }
The output is <h1></h1> only.

I have checked the $data{'testpage'} contains the expected data of either 'A' or 'B'.
What is causing the lack of dereferencing or what else could I try to debug this problem?

Replies are listed 'Best First'.
Re: Dereferencing in blessed object
by LanX (Sage) on Feb 25, 2021 at 23:08 UTC
    > The output is exactly as expected.

    you should use warnings ... always!

    Reference found where even-sized list expected at - line 16.

    the only reason why your output seems to be correct is that you are dereferencing the $vars hash-ref from the closure° not the supposedly passed %vars .

    please note that %vars and $vars are two different variables in separate namespaces.

    try

    my ($value, $vars) = @_;

    and do yourself a favor and write

    $vars->{test}; instead of $$vars{test}

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    °) "global" might be easier to understand

    Update

    Stripped quotes from hash-key

      the only reason why your output seems to be correct is that you are dereferencing the $vars hash-ref from the closure

      Oh!
      Yes, changing the variable name in the subroutine 'breaks' it as expected...now I understand why the different bits of seemingly identical code behave differently! Thanks Rolf.

      $vars->{'test'}; instead of $$vars{test}

      I did have $vars->{'test'}; in there at one point whilst testing it.
      Why is this preferable to $$vars{test}?

        Both are legal syntax, the overwhelming mainstream tends to $vars->{'test'} probably since PBP.

        So many might have problems reading the other form.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        Oh! Yes, changing the variable name in the subroutine 'breaks' it as expected
        To avoid wasting time chasing silly mistakes like these in future, I suggest you always -- as a matter of routine habit -- order your file with functions first and mainline at the end.

        An alternative is to leave the mainline first but put a bare block around it, to ensure mainline global variables don't accidentally leak into the subroutines defined below.

        Why is this preferable to $$vars{test}?

        I don't see objectively why it would be, TBH. If you start getting into deeper structures then the increasing levels of syntax needed to deal with the $$foo{bar} equivalents is going to get messy. For a simple hash though there's little difference.

        Personally I do use the arrow operator as it (subjectively) stands out more clearly to me in an eye-parse. But I do not quote hash keys (whether in references or otherwise) unless necessary. If I see code like $vars->{'test'} it makes me pause and wonder why the key is quoted.

        Whatever you decide to do, make a plan and stick to it. Having your own coding standard, at least within one project, will be a benefit. Inconsistency is the bug's friend.


        🦛

        $$vars{'test'} is a visual pain for me because of the split millisecond where I ask myself about precedence. OTH the -> in $vars->{'test'} dates back to at least C where is used in exactly the same way and context.

        Performance-wise I don't think there is a difference (OSX 10.13 and perl 5.28.3):

        use Benchmark qw( cmpthese ); cmpthese(-5, { deref => 'use strict; use warnings; my $x = { map { $_ => rand + } 1..50 }; $x->{$_} = $_ for 1..100', none => 'use strict; use warnings; my $x = { map { $_ => rand + } 1..50 }; $$x{$_} = $_ for 1..100' }); Rate deref none deref 12483/s -- -1% none 12611/s 1% -- Rate none deref none 11938/s -- -0% deref 11967/s 0% --

        Or,

        use Benchmark qw( cmpthese ); cmpthese(-5, { deref => 'use strict; use warnings; srand 42; my $x = { map { rand() => rand() } 1..50 }; srand 42; $x->{rand()} = rand() for 1..100', none => 'use strict; use warnings; srand 42; my $x = { map { rand() => rand() } 1..50 }; srand 42; $$x{rand()} = rand() for 1..100' });

        For benchmarks see also: https://stackoverflow.com/questions/18984323/how-expensive-is-it-to-dereference-an-array-ref-in-perl

        bw, bliako

      "you should use warnings ... always!"

      Despite being told and shown why this is a good idea, multiple times, it's still not sinking in.

        Understandably ... he's too busy telling us how to improve this site to improve his code... ;-)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Re: Dereferencing in blessed object
by haukex (Bishop) on Feb 26, 2021 at 09:20 UTC
    What is causing the lack of dereferencing or what else could I try to debug this problem?

    The issue with my ($self, $disp, %v) = @_; and my ($value, %vars) = @_; is the same as Re^7: Preparing data for Template. Building an SSCCE to understand it better is a great approach, but since the point of it is also to debug, make sure you pull out all the stops: In this case, Use strict and warnings, use useful variable names, and don't repeat variable names. See also the Basic debugging checklist.

    Here's another way to think about the issue: @_ contains the subroutine arguments, so the first line of reftest can be thought of as my ($value, %vars) = ('testing', $vars);. Drop the $value and you get my %vars = $vars; - there's no dereferencing happening here. In effect, it's the same as my %vars = ( $vars => undef );, which you can see when you dump \%vars with e.g. Data::Dump: you'll see { "HASH(0x...)" => undef }, the hashref was stringified since hash keys are strings.

    Also, variable naming/scoping is biting you as well: $$v{'testpage'} aka $v->{testpage} is accessing a scalar $v, which is not defined in sub process, and so apparently you've got a $v somewhere higher up in the code that is either uninitialized and being autovivified here, or it's already a hashref, or, in the worst case, you're not using strict. And note that if $$v{'testpage'} is giving you undef, "<h1>".$testpage."</h1>\n" would have given you warnings accordingly.

    As before, you need to either explicitly dereference the hashref via my %hash = %$hashref;, although that makes a (shallow) copy of the hash, or you can save on memory and just use the hashref as-is, which is what you're trying to do in $$v{'testpage'}, but to do that, you should've written my ($self, $disp, $v) = @_; instead.

    Just for completeness:

    The only difference is that the subroutine is a method in a blessed object...could this really make a difference?

    No, method calls don't affect this.

      Thanks haukex - that's extremely helpful.

      or, in the worst case, you're not using strict.

      The main script has use strict; but it seems that does then apply to the module it calls...I know that now!

      So now I've added use strict; I get a whole bunch of Global symbol requires explicit package name errors even though they all have my or our declarations. I tracked this down to the declaration happening later in the module than methods that are throwing the error.

      It also highlighted another error with this:

      $db =~ s/_.+?_/_$dbname_/;
      The variable $dbname is declared but in the regexp it is looking for $dbname_. I have solved this for now with:
      my $temp = "_$dbname"."_"; $db =~ s/_.+?_/$temp/;
      But - I feel sure there is a more elegant way!

        Use braces:

        $db =~ s/_.+?_/_${dbname}_/;

        🦛

        The main script has use strict; but it seems that does then apply to the module it calls...I know that now!

        The scope of strict and many other pragmas like warnings is lexical: if you put it at the top of a file, its scope is only that file, and does not extend to any files included with do, require, or use.

        But - I feel sure there is a more elegant way!

        Though I concur with hippo that braces are easiest here, in the spirit of TIMTOWTDI note there's also the /e modifier: $db =~ s/_.+?_/"_$dbname"."_"/e;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11128808]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2022-06-30 19:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My most frequent journeys are powered by:









    Results (98 votes). Check out past polls.

    Notices?