I have an object ($p), and in the initialization I have $this->{list} = [];
Later, I fill up the array with objects of another class (q), and can access them as #{$self{list}} in another subroutine in class [p]. I am trying to sort this array, as
my #slist = sort $self->point_sort, #{$self->{list}};
point_sort is defined as a subroutine in class p, and I am getting
Can't call method "getQval" on an undefined value at p.pm line 64
getQval is a subroutine defined in object q, instances of which populate the {list}. I am trying to do
my $v1 = $a->getQval;
my $v2 = $b->getQval;
in the subroutine point_sort. Any suggestions? TIA.
Edit:
Changed the call to
my #slist = sort { $self->point_sort ($a,$b) } #{$self->{list}};
In point_sort, I have now
my ($c, $d) = #_;
my $val1 = $c->getVarVal;
The error:
Can't locate object method "getVarVal" via package "packageP" at ...
I think it has something to do with packages, not sure what it is. It is looking in package p, whereas I want it to look at package q.
Edit:
I did a print on $c above - perl thinks it is an object of class p - a hashtable
You're not actually using $self->point_sort as a comparison function here. It's being called immediately (with no arguments and before $a and $b are set, hence the error), and its return value (if it got that far) would then be used as the comparator.
The easiest fix is to pass $a and $b explicitly:
my #slist = sort { $self->point_sort($a, $b) } #{$self->{list}};
Then receive them as regular arguments in point_sort.
The syntax of sort are:
sort SUBNAME LIST # Sort the list using named function as the comparison function
sort BLOCK LIST # Sort the list using the block as the comparison function
sort LIST # Sort the list using the default comparison function.
You want $self->point_sort to be used as the comparison function, but you used the third syntax rather than one of the two that allows you to specify a comparison function.
Perhaps you want
sort { $self->point_sort($a, $b) } #{ $self->{list} }
is clear n
Related
I use #_ in a subroutine to get a parameter which is assigned as a reference of an array, but the result dose not showing as an array reference.
My code is down below.
my #aar = (9,8,7,6,5);
my $ref = \#aar;
AAR($ref);
sub AAR {
my $ref = #_;
print "ref = $ref";
}
This will print 1 , not an array reference , but if I replace #_ with shift , the print result will be a reference.
can anyone explain why I can't get a reference using #_ to me ?
This is about context in Perl. It is a crucial aspect of the language.
An expression like
my $var = #ary;
attempts to assign an array to a scalar.
That doesn't make sense as it stands and what happens is that the right-hand side is evaluated to the number of elements of the array and that is assigned to $var.
In order to change that behavior you need to provide the "list context" to the assignment operator.† In this case you'd do
my ($var) = #ary;
and now we have an assignment of a list (of array elements) to a list (of variables, here only $var), where they are assigned one for one. So here the first element of #ary is assigned to $var. Please note that this statement plays loose with the elusive notion of the "list."
So in your case you want
my ($ref) = #_;
and the first element from #_ is assigned to $ref, as needed.
Alternatively, you can remove and return the first element of #_ using shift, in which case the scalar-context assignment is fine
my $ref = shift #_;
In this case you can also do
my $ref = shift;
since shift by default works on #_.
This is useful when you want to remove the first element of input as it's being assigned so that the remaining #_ is well suited for further processing. It is often done in object-oriented code.
It is well worth pointing out that many operators and builtin facilities in Perl act differently depending on what context they are invoked in.
For some specifics, just a few examples: the regex match operator returns true/false (1/empty string) in scalar context but the actual matches in list context,‡ readdir returns a single entry in scalar context but all of them in list context, while localtime shows a bit more distinct difference. This context-sensitive behavior is in every corner of Perl.
User level subroutines can be made to behave that way via wantarray.
†
See Scalar vs List Assignment Operator
for a detailed discussion
‡
See it in perlretut and in perlop for instance
When you assign an array to a scalar, you're getting the size of the array. You pass one argument (a reference to an array) to AAR, that's why you get 1.
To get the actual parameters, place the local variable in braces:
sub AAR {
my ($ref) = #_;
print "ref = $ref\n";
}
This prints something like ref = ARRAY(0x5566c89a4710).
You can then use the reference to access the array elements like this:
print join(", ", #{$ref});
I'm converting perl script to python.
I haven't used perl language before so many things in perl confused me.
For example, below, opt was declared as a scalar first but declared again as a hash. %opt = ();
Is it possible to declare a scalar and a hash with the same name in perl?
As I know, foreach $opt (#opts) means that scalar opt gets values of array opts one by one. opt is an array at this time???
In addition, what does $opt{$opt} mean?
opt outside $opt{$opt} is a hash and opt inside $opt{$opt} is a scalar?
I'm so confused, please help me ...
sub ParseOptions
{
local (#optval) = #_;
local ($opt, #opts, %valFollows, #newargs);
while (#optval) {
$opt = shift(#optval);
push(#opts,$opt);
$valFollows{$opt} = shift(#optval);
}
#optArgs = ();
%opt = ();
arg: while (defined($arg = shift(#ARGV))) {
foreach $opt (#opts) {
if ($arg eq $opt) {
push(#optArgs, $arg);
if ($valFollows{$opt}) {
if (#ARGV == 0) {
&Usage();
}
$opt{$opt} = shift(#ARGV);
push(#optArgs, $opt{$opt});
} else {
$opt{$opt} = 1;
}
next arg;
}
}
push(#newargs,$arg);
}
#ARGV = #newargs;
}
In Perl types SCALAR, ARRAY, and HASH are distinguished by the leading sigil in the variable name, $, #, and % respectively, but otherwise they may bear the same name. So $var and #var and %var are, other than belonging to the same *var typeglob, completely distinct variables.
A key for a hash must be a scalar, let's call it $key. A value in a hash must also be a scalar, and the one corresponding to $key in the hash %h is $h{$key}, the leading $ indicating that this is now a scalar. Much like an element of an array is a scalar, thus $ary[$index].
In foreach $var (#ary) the scalar $var does not really "get values" of array elements but rather aliases them. So if you change it in the loop you change the element of the array.
(Note, you have the array #opts, not #opt.)
A few comments on the code, in the light of common practices in modern Perl
One must always have use warnings; on top. The other one that is a must is use strict, as it enforces declaration of variables with my (or our), promoting all kinds of good behavior. This restricts the scope of lexical (my) variables to the nearest block enclosing the declaration
A declaration may be done inside loops as well, allowing while (my $var = EXPR) {} and foreach my $var (LIST) {}, and then $var is scoped to the loop's block (and is also usable in the rest of the condition)
The local is a different beast altogether, and in this code those should be my instead
Loop labels like arg: are commonly typed in block capitals
The & in front of a function name has rather particular meanings† and is rarely needed. It is almost certainly not needed in this code
Assignment of empty list like my #optArgs = () when the variable is declared (with my) is unneeded and has no effect (with a global #name it may be needed to clear it from higher scope)
In this code there is no need to introduce variables first since they are global and thus created the first time they are used, much like in Python – Unless they are used outside of this sub, in which case they may need to be cleared. That's the thing with globals, they radiate throughout all code
Except for the last two these are unrelated to your Python translation task, for this script.
† It suppresses prototypes; informs interpreter (at runtime) that it's a subroutine and not a "bareword", if it hasn't been already defined (can do that with () after the name); ensures that the user-defined sub is called, if there is a builtin of the same name; passes the caller's #_ (when without parens, &name); in goto &name and defined ...
See, for example, this post and this post
First, to make it clear, in perl, as in shell, you could surround variable names in curly brackets {} :
${bimbo} and $bimbo are the same scalar variable.
#bimbo is an array pointer ;
%bimbo is a hash pointer ;
$bimbo is a scalar (unique value).
To address an array or hash value, you will have to use the '$' :
$bimbo{'index'} is the 'index' value of hash %bimbo.
If $i contains an int, such as 1 for instance,
$bimbo[$i] is the second value of the array #bimbo.
So, as you can see, # or % ALWAYS refers to the whole array, as $bimbo{} or $bimbo[] refers to any value of the hash or array.
${bimbo[4]} refers to the 5th value of the array #bimbo ; %{bimbo{'index'}} refers to the 'index' value of array %bimbo.
Yes, all those structures could have the same name. This is one of the obvious syntax of perl.
And, euhm… always think in perl as a C++ edulcored syntax, it is simplified, but it is C.
Hi I am writing a perl script to accomplish some task.In my script I am using one if loop to compare two strings as shown below.
if($feed_type eq "SE"){
...........}
The above code is not giving me any warning but the output is not as I expected.
Instead of 'eq' if I use '=' I am getting a warning saying expectng '==' but '=' is present. But I am getting the expected output.
Ideally for string comparison I must use 'eq' and for numbers '=='. In this case it's not working. Can anyone figure out what is the problem here?
More info:
This if loop is present in a subroutine. $feed_type is an input for this subroutine. I am reading the input as below:
my $feed_type=#_;
The problem is fixed. I just changed the assignemet statement of feed_type as below
my $feed_type=$_[0];
and it's reading the value as SE and the code is working.
but I still dont know why my $feed_type=$_[0]; didn't work.
= might well work in place of eq, but not for the reason you think.
#!/usr/bin/env perl
use strict;
use warnings;
my $test = "fish";
my $compare = "carrot";
if ( $test = $compare ) {
print "It worked\n";
}
Of course, the problem is - it'll always work, because you're testing the result of an assignment operation.*
* OK, sometimes assignment operations don't work - this is why some coding styles suggest testing if ( 2 == $result ) rather than the other way around.
This is about a core Perl concept: Context. Operators and functions work differently depending on context. In this case:
my $feed_type = #_;
You are assigning an array in scalar context to the variable. An array in scalar context returns its size, not the elements in it. For this assignment to work as you expect, you have to either directly access the scalar value you want, like you have suggested:
my $feed_type = $_[0];
...or you can put your variable in list context by adding parentheses:
my ($feed_type) = #_;
This has the benefit of allowing you to perform complex assignments, like this:
my ($first, $second, #rest) = #_;
So, in short, the problem was that your comparison that looked like this:
if($feed_type eq "SE")
Was actually doing this:
if(1 eq "SE")
And returning false. Which is true. Consider this self-documenting code:
sub foo {
my $size = #_;
if ($size == 1) {
warn "You passed 1 argument to 'foo'\n";
return;
}
}
Which demonstrates the functionality you inadvertently used.
= is used to assign the variable a value, so you would need '==' to compare numerical values and 'eq' for strings.
If it's complaining about not using '==', then it's because $feed_type is not a string.
I can't tell as there's no more code. Whatever $feed_type is set by you need to confirm it actually contains a string or if you're even referencing it correctly.
I've got the following Perl code:
my $wantedips;
# loop through the interfaces
foreach (#$interfaces) {
# local variable called $vlan
my $vlan = $_->{vlan};
# local variable called $cidr
my $cidr = $_->{ip} ."/".$nnm->bits();
# I dont understand this next bit.
# As a rubyist, it looks like a method called $cidr is being called on $wantedips
# But $cidr is already defined as a local variable.
# Why the spooky syntax? Why is $cidr passed as a method to $wantedips?
# what does ->{} do in PERL? Is it some kind of hash syntax?
$wantedips->{$cidr} = $vlan;
# break if condition true
next if ($ips->{$cidr} == $vlan);
# etc
}
The part I don't get is in my comments. Why is $cidr passed to $wantedips, when both are clearly defined as local variables? I'm a rubyist and this is really confusing. I can only guess that $xyz->{$abc}="hello" creates a hash of some sort like so:
$xyz => {
$abc => "hello"
}
I'm new to Perl as you can probably tell.
I don't understand why you are comfortable with
my $vlan = $_->{vlan}
but then
$wantedips->{$cidr} = $vlan
gives you trouble? Both use the same syntax to access hash elements using a hash reference.
The indirection operator -> is used to apply keys, indices, or parameters to a reference value, so you access elements of a hash by its reference with
$href->{vlan}
elements of an array by its reference with
$aref->[42]
and call a code reference with
$cref->(1, 2, 3)
As a convenience, and to make code cleaner, you can remove the indirection operator from the sequences ]->[ and }->{ (and any mixture of brackets and braces). So if you have a nested data structure you can write
my $name = $system->{$ip_address}{name}[2]
instead of
my $name = $system->{$ip_address}->{name}->[2]
#I dont understand this next bit.
$wantedips->{$cidr} = $vlan;
$wantedips is a scalar, specifically it is a hashref (a reference to a hash).
The arrow gets something from inside the reference.
{"keyname"} is how to access a particular key in a hash.
->{"keyname"} is how you access a particular key in a hash ref
$cidr is also a scalar, in this case it is a string.
->{$cidr} accesses a key from a hash ref when the key name is stored in a string.
So to put it all together:
$wantedips->{$cidr} = $vlan; means "Assign the value of $vlan to the key described by the string stored in $cidr on the hash referenced by $wantedips.
I can only guess that $xyz->{$abc}="hello" creates a hash of some sort
like.
Let's break this down to a step by step example that strips out the loops and other bits not directly associated with the code in question.
# Create a hash
my %hash;
# Make it a hashref
my $xyz = \%hash;
# (Those two steps could be done as: my $xyz = {})
# Create a string
my $abc = "Hello";
# Use them together
$xyz->{$abc} = "world";
# Look at the result:
use Data::Dump;
Data::Dump::ddx($xyz);
# Result: { Hello => "world" }
Newbie in Perl again here, trying to understand closure in Perl.
So here's an example of code which I don't understand:
sub make_saying {
my $salute = shift;
my $newfunc = sub {
my $target = shift;
print "$salute, $target!\n";
};
return $newfunc; # Return a closure
}
$f = make_saying("Howdy"); # Create a closure
$g = make_saying("Greetings"); # Create another closure
# Time passes...
$f->("world");
$g->("earthlings");
So my questions are:
If a variable is assigned to a function, is it automatically a reference to that function?
In that above code, can I write $f = \make_saying("Howdy") instead? And when can I use the & because I tried using that in passing the parameters (&$f("world")) but it doesn't work.
and lastly, in that code above how did the strings world and earthlings get appended to the strings Howdy and Greetings.
Note: I understand that $f is somewhat bound to the function with the parameter "Howdy" so that's my understanding how "world" got appended. What I don't understand is the 2nd function inside. How that one operates its magic. Sorry I really don't know how to ask this one.
In Perl, scalar variables cannot hold subroutines directly, they can only hold references. This is very much like scalars cannot hold arrays or hashes, only arrayrefs or hashrefs.
The sub { ... } evaluates to a coderef, so you can directly assign it to a scalar variable. If you want to assign a named function (e.g. foo), you have to obtain the reference like \&foo.
You can call coderefs like $code->(#args) or &$code(#args).
The code
$f = \make_saying("Howdy")
evaluates make_saying("Howdy"), and takes a reference to the returned value. So you get a reference that points to a coderef, not a coderef itself.
Therefore, it can't be called like &$f("world"), you need to dereference one extra level: &$$f("world").
A closure is a function that is bound to a certain environment.
The environment consists of all currently visible variables, so a closure always remembers that scope. In the code
my $x;
sub foo {
my $y;
return sub { "$x, $y" };
}
foo is a closure over $x, as the outer environment consists of $x. The inner sub is a closure over $x and $y.
Each time foo is executed, we get a new $y and therefore a new closure. Most importantly $y does not "go out of scope" when foo is left, but it will be "kept alive" as it's still reachable from the closure returned.
In short: $y is a "local state" of the closure returned.
When we execute make_saying("Howdy"), the $salute variable is set to Howdy. The returned closure remembers that scope.
When we execute it again with make_saying("Greetings"), the body of make_saying is evaluated again. The $salute is now set to Greetings, and the inner sub closes over this variable. This variable is separate from the previous $salute, which still exists, but isn't accessible except through the first closure.
The two greeters have closed over separate $salute variables. When they are executed, their respective $salute is still in scope, and they can access and modify the value.
If a variable is asigned to a function, is it automatically a
reference to that function?
No. In example the function make_saying return reference another function. Such closures do not have name and can catch a variable from outside its scope (variable $salute in your example).
In that above code, can i write $f = \make_saying("Howdy") instead?
And when can i use the & cause i tried using that in passing the
parameters (&$f("world")) but it doesnt work.
No. $f = \make_saying("Howdy") is not what you think (read amon post for details). You can write $f = \&make_saying; which means "put into $f reference to function make_saying". You can use it later like this:
my $f = \&make_saying;
my $other_f = $f->("Howdy");
$other_f->("world");
and lastly, In that code above how in he** did the words world and
earthlings got appended to the words howdy and greetings.
make_saying creating my variable which goes into lamda (my $newfunc = sub); that lambda is returned from make_saying. It holds the given word "Howdy" through "closing" (? sorry dont know which word in english).
Every time you call the subroutine 'make_saying', it:
creates a DIFFERENT closure
assigns the received parameter to the scalar '$salute'
defines (creates but not execute) an inner anonymous subroutine:
That is the reason why at that moment nothing is assigned to the scalar
$target nor is the statement print "$salute, $target!\n"; executed .
finally the subroutine 'make_saying' returns a reference to the inner anonymous subroutine, that reference becomes the only way to call the (specific) anonymous subroutine.
Ever time you call each anonymous subroutine, it:
assign the received parameter to the scalar $target
sees also the scalar $salute that will have the value assigned at the moment in which was created the anonymous subroutine (when was called its parent subroutine make_saying
finally executes the statement print "$salute, $target!\n";