Odd number of elements in hash assignment error - perl

I was learning Perl Objects. I wrote a simple constructor in a module file create_schedules.pm:
#!/usr/bin/perl -w
#
package create_schedules;
use strict;
use warnings;
use diagnostics;
sub new {
my $class = shift;
my %params = #_;
my $self=bless{
_para1=>$params{'mypara1'},
_para2=>$params{'mypara2'}
},$class;
return $self;
}
1;
and I am creating an object in a main file main.pl:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use lib::my_module;
sub _start(){
print "Main Function Started\n";
create_schedules::new(
'mypara1' => 'This is mypara1',
'mypara2' => 'This is mypara2',
);
}
_start();
As soon as I run main.pl, I got following error:
Main Function Started
Odd number of elements in hash assignment at lib/create_schedules.pm line 9 (#1)
(W misc) You specified an odd number of elements to initialize a hash,
which is odd, because hashes come in key/value pairs.

Just call with:
create_schedules->new
# note ___^^
An old way to call was:
new create_schedules(...);
Why your code is wrong:
In the new method you're doing my $class = shift;, after that, #_ will contain only 3 elements:
'This is mypara1',
'mypara2',
'This is mypara2',
Then the instruction my %params = #_; will cause the warning about odd number of elements.

You used the function directly, not as an object:
create_schedules::new
#^^-- this
Instead of
create_schedules->new
When you do that, this line:
my $class = shift;
Does not contain the object, but the first element of your hash assignment. And if you remove one element, the list is now a number of elements that is odd.
Although I do note that your package names are not the same. You are using create_schedules in the main, and my_module in the module.

Related

FATAL uninitialized warnings - action at a distance

I recently hit a bug when use warnings FATAL ... pragma interprets mute warnings from elsewhere as a reason to die. Consider the following sample:
use strict;
# In one file:
no warnings;
my %hash;
Foo->bar( my $temp = $hash{ +undef } ); # this lives
Foo->bar( $hash{ +undef } ); # this dies
# Elsewhere
package Foo;
use warnings FATAL => qw(uninitialized);
sub bar {
my ($self, $param) = #_; # prefectly safe
$param = "(undef)"
unless defined $param; # even safer
print "Param: $param\n";
}
Now this of course can be fixed big time using the same policy regarding warnings throughout the project. Or this can be fixed every time it occurs by ruling out undefs in specific places (see # this lives line).
My question is whether there is an acceptable solution for package Foo which doesn't require changing anything that calls it, and whether this is really a bug in Perl itself.
It's not a bug. You are experiencing a side-effect of a feature that prevents needless autovification of hash elements passed to subs.
Perl passes by reference. That means that changes to the arguments within the function will change the parameters on the outside.
$ perl -E'
sub f { $_[0] = "xyz"; }
f($x);
say $x;
'
xyz
This applies to hash elements too.
$ perl -E'
sub f { $_[0] = "xyz"; }
my %h;
f($h{x});
say $h{x};
'
xyz
The sub doesn't know anything about the hash, so the hash element must be created before the sub is entered for there to be something to which to assign.
...or does it? It would be generally undesirable for f($h{x}) to always create $h{x} if the element doesn't exist. As such, Perl postpones doing the hash lookup until $_[0] is accessed, at which point it's known whether the element needs to be vivified or not. This is why the warning is coming from within the sub.
Specifically, Perl doesn't pass $h{x} to the sub when you call f($h{x}). Instead, it passes a magical scalar that contains both a reference to %h and the key value (x). This postpones doing the hash lookup until $_[0] is accessed, where it's known whether $_[0] is used somewhere assignable or not.
If $_[0] is used in a manner in which it doesn't change (i.e. if it's used as an rvalue), the hash element is looked up without vivifying it.
If $_[0] is used in a manner in which it can change (i.e. if it's used as an lvalue), the hash element is vivified and returned.
$ perl -E'
sub f { my $x = $_[0]; } # $_[0] returns undef without vivifying $h{x}
sub g { $_[0] = "xyz"; } # $_[0] vivifies and returns $h{x}
my %h;
f($h{x});
say 0+keys(%h);
g($h{x});
say 0+keys(%h);
'
0
1

Not able to print value using reference inside function in perl

Why am i not being able to print the value using reference when its inside function?
sub fun {
$ref = #_;
print "\n Inside the function $ref->[1] \n";
}
my #arr=(2,3,4);
fun (\#arr);
my $ref2 = \#arr;
print "\n$ref2->[1]\n";
Output i get is :
Inside the function
3
It is your assignment that is wrong:
$ref = #_;
Because in scalar context, an array returns its size, not its elements. Scalar context is imposed when you have a scalar value on the left hand side. You should do:
my ($ref) = #_;
Or
my $ref = shift; # shifts first argument from #_
You also need to change $ref->[1] to $ref->[0], or you will refer to the wrong element. Perl arrays start at index 0.
What you should have done is to use
use strict;
use warnings;
Which would have given you the error:
Can't use string ("1") as an ARRAY ref while "strict refs" in use at line ...
Which is what happens. You assign the size 1 to $ref, and then try to use it as an array ref: $ref->[1]

How do you lock a member variable in perl?

I wrote a script in perl which does multi-threading, I then tried to convert it over into an object. However, I can't seem to figure out how to lock on a member variable. The closest I've come to is:
#!/usr/bin/perl
package Y;
use warnings;
use strict;
use threads;
use threads::shared;
sub new
{
my $class = shift;
my $val :shared = 0;
my $self =
{
x => \$val
};
bless $self, $class;
is_shared($self->{x}) or die "nope";
return $self;
}
package MAIN;
use warnings;
use strict;
use threads;
use threads::shared;
use Data::Dumper;
my $x = new Y();
{
lock($x->{x});
}
print Dumper('0'); # prints: $VAR = '0';
print Dumper($x->{x}); # prints: $VAR = \'0';
print "yes\n" if ($x->{x} == 0); # prints nothing
#print "yes\n" if ($$x->{x} == 0); # dies with msg: Not a SCALAR reference
my $tmp = $x->{x}; # this works. Must be a order of precedence thing.
print "yes\n" if ($$tmp == 0); # prints: yes
#++$$x->{x}; # dies with msg: Not a SCALAR reference
++$$tmp;
print Dumper($x->{x}); # prints: $VAR = \'1';
This allows me to put a lock on the member var x, but it means I'd be needing 2 member variables as the actual member var isn't really capable of being manipulated by assigning to it, incrementing it, etc. I can't even test against it.
EDIT:
I'm thinking that I should rename this question "How do you dereference a member variable in perl?" as the problem seems to boil down to that. Using $$x->{x} is invalid syntax and you can't force precedence rules with parentheses. I.e. $($x->{x}) doesn't work. Using a temporary works but it a nuisance.
I don't get what you are trying to do with threads and locking, but there are some simple errors in the way you use references.
$x->{x}
is a reference to a scalar, so the expressions
$x->{x} == 0
++$$x->{x}
both look suspect. $$x->{x} is parsed as {$$x}->{x} (dereference $x, then treat it as a hash reference and look up the value with key x). I think you mean to say
${$x->{x}} == 0
++${$x->{x}}
where ${$x->{x}} means to treat $x as a hash reference, to look up the value for key x in that hash, and then to dererence that value.

Why does Test::MockObject make thawing my objects throw warnings?

This one needs a bit of explanation to start with. I've got a unit test where I save Class::Std::Fast::Storable objects that come from SOAP::WSDL using Storable. The object I am storing is the result of a webservice call. It ends up being encoded with MIME::Base64 and written somewhere to a file. This is working great.
When I was building up the unit test, I needed to use Test::MockObject to mock the call that webservice, thus returning the restored object. But somehow this is throwing a bunch of warnings about the use of uninitialized value in hash element.
I tried recreating it as a small example. This first bit of code is how I get the base64 output for the example. We will use it in a minute.
use strict;
use warnings;
use MIME::Base64;
use Storable;
use SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType;
my $object = SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType->new;
$object->set_value('foo');
print encode_base64(Storable::freeze($object));
So we got three lines of base64. Let's try to restore them:
use strict;
use warnings;
use MIME::Base64;
use Storable;
use Test::Simple tests => 1;
local $/ = undef;
my $object = Storable::thaw(decode_base64(<DATA>));
ok( $object->get_value, 'foo' );
__DATA__
BAgIMTIzNDU2NzgECAgIE0ADAQAAAAQDAQAAAAoDZm9vBQAAAHZhbHVlMAAAAFNPQVA6OldTREw6
OlhTRDo6VHlwZWxpYjo6QnVpbHRpbjo6YW55U2ltcGxlVHlwZYAwU09BUDo6V1NETDo6WFNEOjpU
eXBlbGliOjpCdWlsdGluOjphbnlTaW1wbGVUeXBlEAQICDEyMzQ1Njc4BAgICAUBAAAAAQ==
Neat. It works!
~> perl foo.t
1..1
ok 1 - foo
Now let's add Test::MockObject.
use strict;
use warnings;
use MIME::Base64;
use Storable;
use Test::Simple tests => 1;
use Test::MockObject; # <------- only line I changed
local $/ = undef;
my $object = Storable::thaw(decode_base64(<DATA>));
ok( $object->get_value, 'foo' );
__DATA__
BAgIMTIzNDU2NzgECAgIE0ADAQAAAAQDAQAAAAoDZm9vBQAAAHZhbHVlMAAAAFNPQVA6OldTREw6
OlhTRDo6VHlwZWxpYjo6QnVpbHRpbjo6YW55U2ltcGxlVHlwZYAwU09BUDo6V1NETDo6WFNEOjpU
eXBlbGliOjpCdWlsdGluOjphbnlTaW1wbGVUeXBlEAQICDEyMzQ1Njc4BAgICAUBAAAAAQ==
Ok, this is weird. It works, but it throws an error.
1..1
Use of uninitialized value in hash element at /usr/lib/perl5/site_perl/5.16.2/SOAP/WSDL/XSD/Typelib/Builtin/anySimpleType.pm line 53, <DATA> chunk 1.
ok 1 - foo
So I looked at line 53 of anySimpleType.pm, and it says:
my $OBJECT_CACHE_REF = Class::Std::Fast::OBJECT_CACHE_REF();
sub new {
my $self = pop #{ $OBJECT_CACHE_REF->{ $_[0] } }; # <-- here
$self = bless \(my $o = Class::Std::Fast::ID()), $_[0]
if not defined $self;
Hmm. $_[0] is undef. Looks like new was called without an argument.
But how the hell can loading Test::MockObject do that? Or maybe that warning is always popping up, but somehow it was not shown before? I debugged it a little, and it turns out the warning is always showing in Komodo IDEs debugger, regardless of what I loaded.
However, it only shows up in the normal program output if I have Test::MockObject loaded as well. Can anyone explain that to me?
I still don't know why this is happening exactly. My debugging led me to believe that the initialization warnings are always thrown by these Storable objects. However, they are silent if Test::MockObject is not there.
So the workaround to get it to shut up is as follows:
local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /uninitialized/};
local $/ = undef;
my $object = Storable::thaw(decode_base64(<DATA>));
ok( $object->get_value, 'foo' );

Perl OOP Blessing

I'm new to Perl and I've been making my way through this tutorial http://qntm.org/files/perl/perl.html
Anyways, I'm working on creating a package that will take in a matrix and will perform various basic operations (i.e. gaussian elimination, rref, back sub, deterimants, etc). I have my constructor taking in a list of references, but I'm having some trouble blessing them so I can access them later. My code thus far:
main.pl:
use strict;
use warnings;
use Matrix;
my #list = ([1,1,1],[2,2,2]);
my $matrix = Matrix->new(#list);
$matrix->test();
Matrix.pm:
package Matrix;
sub new(){
my $class = shift;
my $self = [];
my #params = #_;
$self = \#params;
print scalar #{$self->[1]}; #just testing some output...(outputs 3 as expected)
bless $self,$class;
return $self;
}
sub test(){
print #{$self->[1]}; #does not output anything
}
1;
I'm assuming the problem is that the references that $self is referring to is not being blessed, but I'm not sure how to do this. Any help would be appreciated.
Thanks
You forgot to actually define $self in test; it's not available for you automatically. This is why you should always put use warnings; use strict; in every Perl source file: so that the compiler will tell you about errors like these. (Also, there's no point in writing sub new() instead of sub new, and likewise for test; the function prototype is not only wrong but will be flat-out ignored when new is used as a method, i.e., how new is supposed to be used.)