Can anyone tell me why this prints REF(*) instead of 0?
$a = 0;
$a = \$a;
print $$a . "\n";
Erm, because $a doesn't contain 0 any more, but instead a reference to itself. You overwrote it in the second line!
If you want to set $a to a reference to $a's original value then you can write
$a = \"$a"
which works by using an expression that happens to evaluate to the value of $a, and taking a reference to that. This will fail if $a starts out as something other than a simple string or number, such as a reference or any value which changes when it is stringified. Then you could write an identity function such as
sub i { shift }
and use
$a = \i($a)
Your last assignment makes $a to reference to itself, so dereferencing it makes sense as chasing own tail in circular manner,
use warnings;
use Data::Dumper;
$a = 0;
$a = \$a;
print Dumper $a;
output
$VAR1 = \$VAR1;
You might want to make reference to a list of values which does what you want,
($a) = \map { $_ } $a;
print Dumper $a;
output
$VAR1 = \0;
Related
I tried to find the error myself, but don't see it. The following code produces warnings (same problem in Perl 5.18.2 and 5.32.1).
Use of uninitialized value in numeric comparison (<=>) at test.pl line 14.
while the comparison function of the sort is performed (and, as a consequence, the sort operation is not performed correctly). As far as I see, no value of the hash is initial, they all have defined numeric values.
use strict;
use warnings;
# Sort the occurrences of letters in a list of words, highest count first.
my #words = ('ACGT','CCGT','CATG'); # Just an example
my $a = join '',#words;
my $l = length $a;
my %count = ();
for (my $i = 0; $i < $l; $i++) {
my $x = substr( $a, $i, 1);
$count{$x}++;
}
for my $x (sort { $count{$b} <=> $count{$a} } keys %count) {
print "$x: $count{$x}\n";
}
Remark : it didn't help adding the hash element creation line before incrementing it with the $count{$x}++; statement - same result (expectedly, as undef counts like 0 for the increment operation):
...
$count{$x} = 0 unless defined $count{$x};
$count{$x}++;
...
Normally, the sort function uses two package variables called $a and $b to do the sorting. Specifically, sort sets the variables called $a and $b on the current package to be the current sort values. Those are not arguments to your { $count{$b} <=> $count{$a} } block; they're global variables in the current package.
Now, $b is fine. Since you never do anything else with it, Perl picks up the package variable just fine. But you declared a lexical (my) variable called $a earlier in your code, and that lexical is shadowing the package variable.
So sort is setting a variable called, effectively, $YourPackage::a, and your code is accessing a local variable called my $a, which is unrelated to the other one.
You can fix this by changing the my $a = join '',#words; variable to be called something else, and in fact you should probably do that. The names $a, $b, and $_ are used for things like this indiscriminately in Perl for historical reasons, so it's probably best to never have your own variables named any of those names.
But if you don't want to (or can't) change any of the rest of the code, you can expose the package variable with our.
for my $x (sort { our $a; $count{$b} <=> $count{$a} } keys %count) {
...
}
My understanding was that in Perl we pass hashes to functions by reference
Consider the following example, where we modify the hash in the modifyHash function
#!/usr/local/bin/perl
my %hash;
$hash{"A"} = "1";
$hash{"B"} = "2";
print (keys %hash);
print "\n";
modifyHash(\%hash);
print (keys %hash);
print "\n";
sub modifyHash {
my $hashRef = #_[0];
my %myHash = %$hashRef;
$myHash{"C"} = "3";
print (keys %myHash);
print "\n";
}
The output of this script is:
AB
ABC
AB
I would have expected it to be:
AB
ABC
ABC
...as we pass the hash by reference.
What concept am I missing here about passing hashes to functions?
That's because when you do my %myHash = %$hashRef;, you're taking a copy of the dereferenced $hashref and putting it into %myHash which is the same thing as my %myHash = %hash;, so you're not working on the referenced hash at all.
To work on the hash specified by the reference, try this...
sub modifyHash {
my $hashRef = $_[0];
$hashRef->{"C"} = "3";
print (keys %$hashRef);
print "\n";
}
As pointed out by ThisSuitIsBlackNot in the comments below, #_[0] is better written as $_[0]. You should always be using use strict; and use warnings;, as this would have been caught. Because you're sending in a reference, you could also have used my $hashRef = shift;.
The problem is with the assignment:
my %myHash = %$hashRef;
This is akin to saying:
$x = 5;
$y = $x;
You're not setting $y to reference the same spot in memory, you're just giving the value of $x to $y. In your example, you're creating a new hash (%myHash) and giving it the value of the hash stored at $hashRef. Any future changes are to the new hash, not the original.
If you want to manipulate the original, you should do something like:
${$hashRef}{"C"} = "3";
or
$hashRef->{"D"} = 4;
There might be a more elegant way of doing it, but as far as I know you want to work with the hash reference.
I have never used Perl, but I need to complete this exercise. My task is to sort an array in a few different ways. I've been provided with a test script. This script puts together the array and prints statements for each stage of it's sorting. I've named it foo.pl:
use strict;
use warnings;
use MyIxHash;
my %myhash;
my $t = tie(%myhash, "MyIxHash", 'a' => 1, 'abe' => 2, 'cat'=>'3');
$myhash{b} = 4;
$myhash{da} = 5;
$myhash{bob} = 6;
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the starting key => val pairs\n";
$t->SortByKey; # sort alphabetically
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the alphabetized key => val pairs\n";
$t->SortKeyByFunc(sub {my ($a, $b) = #_; return ($b cmp $a)}); # sort alphabetically in reverse order
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the reverse alphabetized key => val pairs\n";
$t->SortKeyByFunc(\&abcByLength); # use abcByLength to sort
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the abcByLength sorted key => val pairs\n";
print "Done\n\n";
sub abcByLength {
my ($a, $b) = #_;
if(length($a) == length($b)) { return $a cmp $b; }
else { return length($a) <=> length($b) }
}
Foo.pl uses a package called MyIxHash which I've created a module for called MyIxHash.pm. The script runs through the alphabetical sort: "SortByKey", which I've inherited via the "IxHash" package in my module. The last two sorts are the ones giving me issues. When the sub I've created: "SortKeyByFunc" is ran on the array, it passes in the array and a subroutine as arguments. I've attempted to take those arguments and associate them with variables.
The final sort is supposed to sort by string length, then alphabetically. A subroutine for this is provided at the bottom of foo.pl as "abcByLength". In the same way as the reverse alpha sort, this subroutine is being passed as a parameter to my SortKeyByFunc subroutine.
For both of these sorts, it seems the actual sorting work is done for me, and I just need to apply this subroutine to my array.
My main issue here seems to be that I don't know how, if possible, to take my subroutine argument and run my array through it as a parameter. I'm a running my method on my array incorrectly?
package MyIxHash;
#use strict;
use warnings;
use parent Tie::IxHash;
use Data::Dumper qw(Dumper);
sub SortKeyByFunc {
#my $class = shift;
my ($a, $b) = #_;
#this is a reference to the already alphabetaized array being passed in
my #letters = $_[0][1];
#this is a reference to the sub being passed in as a parameter
my $reverse = $_[1];
#this is my variable to contain my reverse sorted array
my #sorted = #letters->$reverse();
return #sorted;
}
1;
"My problem occurs where I try: my #sorted = #letters->$reverse(); I've also tried: my #sorted = sort {$reverse} #letters;"
You were really close; the correct syntax is:
my $reverse = sub { $b cmp $a };
# ...
my #sorted = sort $reverse #letters;
Also note that, for what are basically historical reasons, sort passes the arguments to the comparison function in the (slightly) magic globals $a and $b, not in #_, so you don't need to (and indeed shouldn't) do my ($a, $b) = #_; in your sortsubs (unless you declare them with a prototype; see perldoc -f sort for the gritty details).
Edit: If you're given a comparison function that for some reason does expect its arguments in #_, and you can't change the definition of that function, then your best bet is probably to wrap it in a closure like this:
my $fixed_sortsub = sub { $weird_sortsub->($a, $b) };
my #sorted = sort $fixed_sortsub #letters;
or simply:
my #sorted = sort { $weird_sortsub->($a, $b) } #letters;
Edit 2: Ah, I see the/a problem. When you write:
my #letters = $_[0][1];
what you end up with a is a single-element array containing whatever $_[0][1] is, which is presumably an array reference. You should either dereference it immediately, like this:
my #letters = #{ $_[0][1] };
or just keep is as a reference for now and dereference it when you use it:
my $letters = $_[0][1];
# ...
my #sorted = sort $whatever #$letters;
Edit 3: Once you do manage to sort the keys, then, as duskwuff notes in his original answer, you'll also need to call the Reorder() method from your parent class, Tie::IxHash to actually change the order of the keys. Also, the first line:
my ($a, $b) = #_;
is completely out of place in what's supposed to be an object method that takes a code reference (and, in fact, lexicalizing $a and $b is a bad idea anyway if you want to call sort later in the same code block). What it should read is something like:
my ($self, $sortfunc) = #_;
In fact, rather than enumerating all the things that seem to be wrong with your original code, it might be easier to just fix it:
package MyIxHash;
use strict;
use warnings;
use parent 'Tie::IxHash';
sub SortKeyByFunc {
my ($self, $sortfunc) = #_;
my #unsorted = $self->Keys();
my #sorted = sort { $sortfunc->($a, $b) } #unsorted;
$self->Reorder( #sorted );
}
1;
or simply:
sub SortKeyByFunc {
my ($self, $sortfunc) = #_;
$self->Reorder( sort { $sortfunc->($a, $b) } $self->Keys() );
}
(Ps. I now see why the comparison functions were specified as taking their arguments in #_ rather than in the globals $a and $b where sort normally puts them: it's because the comparison functions belong to a different package, and $a and $b are not magical enough to be the same in every package like, say, $_ and #_ are. I guess that could be worked around, but it would take some quite non-trivial trickery with caller.)
(Pps. Please do credit me and duskwuff / Stack Overflow when you hand in your exercise. And good luck with learning Perl — trust me, it'll be a useful skill to have.)
Your SortKeyByFunc method returns the results of sorting the array (#sorted), but it doesn't modify the array "in place". As a result, just calling $t->SortKeyByFunc(...); doesn't end up having any visible permanent effects.
You'll need to call $t->Reorder() within your SortKeyByFunc method to have any lasting impact on the array. I haven't tried it, but something like:
$t->Reorder(#sorted);
at the end of your method may be sufficient.
Consider the following Perl code.
#!/usr/bin/perl
use strict;
use warnings;
$b="1";
my $a="${b}";
$b="2";
print $a;
The script obviously outputs 1. I would like it to be whatever the current value of $b is.
What would be the smartest way in Perl to achieve lazy evaluation like this? I would like the ${b} to remain "unreplaced" until $a is needed.
I'm more interested in knowing why you want to do this. You could use a variety of approaches depending on what you really need to do.
You could wrap up the code in a coderef, and only evaluate it when you need it:
use strict; use warnings;
my $b = '1';
my $a = sub { $b };
$b = '2';
print $a->();
A variant of this would be to use a named function as a closure (this is probably the best approach, in the larger context of your calling code):
my $b = '1';
sub print_b
{
print $b;
}
$b = '2';
print_b();
You could use a reference to the original variable, and dereference it as needed:
my $b = '1';
my $a = \$b;
$b = '2';
print $$a;
What you want is not lazy evaluation, but late binding. To get it in Perl, you need to use eval.
my $number = 3;
my $val = "";
my $x = '$val="${number}"';
$number = 42;
eval $x;
print "val is now $val\n";
Be advised that eval is usually inefficient as well as methodically atrocious. You are almost certainly better off using a solution from one of the other answers.
Perl will interpolate a string when the code runs, and i don't know of a way to make it not do so, short of formats (which are ugly IMO). What you could do, though, is change "when the code runs" to something more convenient, by wrapping the string in a sub and calling it when you need the string interpolated...
$b = "1";
my $a = sub { "\$b is $b" };
$b = "2";
print &$a;
Or, you could do some eval magic, but it's a bit more intrusive (you'd need to do some manipulation of the string in order to achieve it).
As others have mentioned, Perl will only evaluate strings as you have written them using eval to invoke the compiler at runtime. You could use references as pointed out in some other answers, but that changes the way the code looks ($$a vs $a). However, this being Perl, there is a way to hide advanced functionality behind a simple variable, by using tie.
{package Lazy;
sub TIESCALAR {bless \$_[1]} # store a reference to $b
sub FETCH {${$_[0]}} # dereference $b
sub STORE {${$_[0]} = $_[1]} # dereference $b and assign to it
sub new {tie $_[1] => $_[0], $_[2]} # syntactic sugar
}
my $b = 1;
Lazy->new( my $a => $b ); # '=>' or ',' but not '='
print "$a\n"; # prints 1
$b = 2;
print "$a\n"; # prints 2
You can lookup the documentation for tie, but in a nutshell, it allows you to define your own implementation of a variable (for scalars, arrays, hashes, or file handles). So this code creates the new variable $a with an implementation that gets or sets the current value of $b (by storing a reference to $b internally). The new method is not strictly needed (the constructor is actually TIESCALAR) but is provided as syntactic sugar to avoid having to use tie directly in the calling code.
(which would be tie my $a, 'Lazy', $b;)
You wish to pretend that $a refers to something that is evaluated when $a is used... You can only do that if $a is not truly a scalar, it could be a function (as cHao's answer) or, in this simple case, a reference to the other variable
my $b="1";
my $a= \$b;
$b="2";
print $$a;
I would like the ${b} to remain "unreplaced" until $a is needed.
Then I'd recommend eschewing string interpolation, instead using sprintf, so that you "interpolate" when needed.
Of course, on this basis you could tie together something quick(ish) and dirty:
use strict;
use warnings;
package LazySprintf;
# oh, yuck
sub TIESCALAR { my $class = shift; bless \#_, $class; }
sub FETCH { my $self = shift; sprintf $self->[0], #$self[1..$#$self]; }
package main;
my $var = "foo";
tie my $lazy, 'LazySprintf', '%s', $var;
print "$lazy\n"; # prints "foo\n"
$var = "bar";
print "$lazy\n"; # prints "bar\n";
Works with more exotic format specifiers, too. Yuck.
OK, I have the following code:
use strict;
my #ar = (1, 2, 3);
foreach my $a (#ar)
{
$a = $a + 1;
}
print join ", ", #ar;
and the output?
2, 3, 4
What the heck? Why does it do that? Will this always happen? is $a not really a local variable? What where they thinking?
Perl has lots of these almost-odd syntax things which greatly simplify common tasks (like iterating over a list and changing the contents in some way), but can trip you up if you're not aware of them.
$a is aliased to the value in the array - this allows you to modify the array inside the loop. If you don't want to do that, don't modify $a.
See perldoc perlsyn:
If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.
There is nothing weird or odd about a documented language feature although I do find it odd how many people refuse check the docs upon encountering behavior they do not understand.
$a in this case is an alias to the array element. Just don't have $a = in your code and you won't modify the array. :-)
If I remember correctly, map, grep, etc. all have the same aliasing behaviour.
As others have said, this is documented.
My understanding is that the aliasing behavior of #_, for, map and grep provides a speed and memory optimization as well as providing interesting possibilities for the creative. What happens is essentially, a pass-by-reference invocation of the construct's block. This saves time and memory by avoiding unnecessary data copying.
use strict;
use warnings;
use List::MoreUtils qw(apply);
my #array = qw( cat dog horse kanagaroo );
foo(#array);
print join "\n", '', 'foo()', #array;
my #mapped = map { s/oo/ee/g } #array;
print join "\n", '', 'map-array', #array;
print join "\n", '', 'map-mapped', #mapped;
my #applied = apply { s/fee//g } #array;
print join "\n", '', 'apply-array', #array;
print join "\n", '', 'apply-applied', #applied;
sub foo {
$_ .= 'foo' for #_;
}
Note the use of List::MoreUtils apply function. It works like map but makes a copy of the topic variable, rather than using a reference. If you hate writing code like:
my #foo = map { my $f = $_; $f =~ s/foo/bar/ } #bar;
you'll love apply, which makes it into:
my #foo = apply { s/foo/bar/ } #bar;
Something to watch out for: if you pass read only values into one of these constructs that modifies its input values, you will get a "Modification of a read-only value attempted" error.
perl -e '$_++ for "o"'
the important distinction here is that when you declare a my variable in the initialization section of a for loop, it seems to share some properties of both locals and lexicals (someone with more knowledge of the internals care to clarify?)
my #src = 1 .. 10;
for my $x (#src) {
# $x is an alias to elements of #src
}
for (#src) {
my $x = $_;
# $_ is an alias but $x is not an alias
}
the interesting side effect of this is that in the first case, a sub{} defined within the for loop is a closure around whatever element of the list $x was aliased to. knowing this, it is possible (although a bit odd) to close around an aliased value which could even be a global, which I don't think is possible with any other construct.
our #global = 1 .. 10;
my #subs;
for my $x (#global) {
push #subs, sub {++$x}
}
$subs[5](); # modifies the #global array
Your $a is simply being used as an alias for each element of the list as you loop over it. It's being used in place of $_. You can tell that $a is not a local variable because it is declared outside of the block.
It's more obvious why assigning to $a changes the contents of the list if you think about it as being a stand in for $_ (which is what it is). In fact, $_ doesn't exist if you define your own iterator like that.
foreach my $a (1..10)
print $_; # error
}
If you're wondering what the point is, consider the case:
my #row = (1..10);
my #col = (1..10);
foreach (#row){
print $_;
foreach(#col){
print $_;
}
}
In this case it is more readable to provide a friendlier name for $_
foreach my $x (#row){
print $x;
foreach my $y (#col){
print $y;
}
}
Try
foreach my $a (#_ = #ar)
now modifying $a does not modify #ar.
Works for me on v5.20.2