Re: Dereferencing in blessed object
by LanX (Saint) 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}
°) "global" might be easier to understand
Update
Stripped quotes from hash-key | [reply] [Watch: Dir/Any] [d/l] [select] |
|
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}?
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
|
|
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
|
|
|
|
$$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
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
"you should use warnings ... always!"
Despite being told and shown why this is a good idea, multiple times, it's still not sinking in.
| [reply] [Watch: Dir/Any] |
|
Understandably ... he's too busy telling us how to improve this site to improve his code... ;-)
| [reply] [Watch: Dir/Any] |
|
|
|
Re: Dereferencing in blessed object
by haukex (Archbishop) 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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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! | [reply] [Watch: Dir/Any] [d/l] [select] |
|
$db =~ s/_.+?_/_${dbname}_/;
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
|
|
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;
| [reply] [Watch: Dir/Any] [d/l] [select] |