array deepcopy instead of reference in perl object - perl

i tried several hours to store a sub array into an object and failed. maybe someone of you can show me how to store a deep copy with perl.
sry i dont know if this question is clear, but should be easy to solve...
here the example.
here the object class
package obj;
use strict;
use warnings;
require Exporter;
our #ISA = qw(Exporter);
sub new(\#){
my $class=shift;
my $this={};
$this->{"array"}=shift;
return bless($this,$class);
}
sub getArray(){
my $this=shift;
return $this->{"array"};
}
and the test class
use strict;
use warnings;
use obj;
my #a=(1,2);
push #a,3;
my $ob=obj->new(\#a);
#a=();
print #{$ob->getArray()};
this returns nothing - does not shift dereference the array?
so how to do this?
thx

Deference what array? The only array involved in the shift is #_? $_[0] is a scalar, not an array.
A (shallow) array copy is done using:
#dst = #src;
so you want
#{ $this->{"array"} } = #{ shift };
If you truly want an deep copy (though there's no need for it in your example), use
use Storable qw( dclone );
$this->{"array"} = dclone(shift);

Related

Perl : Like in java we can access public member (variables) in other class is there any same concept in perl

I have 2 perl file and i want to use value of one variable in another perl file as input so how i can do it is there any concept like java we can declare it as public and use it.
any help appreciated thank you!
In this answer, I'll skip the discussion about whether it is the right decision to use OOP or not and just assume you want to do it the OOP-way.
In short, all variables of an object in Perl can be considered public. In fact, the problem is often the opposite - to make some of them private. Anyway, if you have a file Obj.pm which defines an object with a field foo which looks like this:
package Obj;
sub new {
my $class = shift;
my $self = {foo => "bar"};
bless $self, $class;
return $self;
}
you can access the foo variable as if it were public:
use Obj;
my $obj = Obj->new();
print $obj->{foo};
For perhaps a more pleasant OOP in Perl, look at the Moose package which gives you more flexibility.
As #user2864740 pointed you don't need "OO" in perl to share variables.It is one way, Let's say you have two files
Foo.pm(package):
#!/usr/bin/perl
use strict;
use warnings;
use Exporter;
package Foo;
our #ISA = qw(Exporter);
our #EXPORT = qw( blat); #exported by default
our #EXPORT_OK = qw(bar );#not exported by default
our $x="42";#variable to be shared should be "our" not "my"
sub bar {
print "Hello $_[0]\n"
}
sub blat {
print "World $_[0]\n"
}
1;
Access that variable from other file as
bar.pl :
#!/usr/bin/perl
use strict;
use warnings;
use Foo;
print "$Foo::x";#imported variable
blat("hello");#imported subroutine
If you want to import listed functions then:
#!/usr/bin/perl
use strict;
use warnings;
use Foo qw(bar blat);# import listed subs
print "$Foo::x";#imported variable
blat("hello ");#imported subroutine
bar("hi");#this also get imported

Pass a subroutine to module and redefine it?

I'm trying to create a module with a method that receives a subroutine and redefines it. I had no problem redefining a subroutine inside the main script but the same syntax doesn't seem to work inside the method:
main.pl
use strict;
use warnings;
use ReDef;
sub orig{
print "Original!\n";
}
orig;
*orig=sub{print "not Original!\n";};
orig;
ReDef::redef(\&orig);
orig;
ReDef.pm
package ReDef;
use strict;
use warnings;
sub redef {
my $ref=shift;
*ref = sub {print "Redefined!";}
}
1;
Test output:
perl main.pl
Original!
Subroutine main::orig redefined at main.pl line 9.
not Original!
not Original!
ReDef::redef() doesn't redefine. The way I see it, the *ref is a coderef and assigning to it another subroutine should change main::orig();
What is the correct syntax?
Your redef function should be like this:
package ReDef;
use strict;
use warnings;
sub redef {
my $ref = shift;
no warnings qw(redefine);
*$ref = sub { print "Redefined!" };
}
And you should NOT call it like this:
ReDef::redef(\&orig);
Instead, you must call it like this:
ReDef::redef(\*orig);
Why? When you call orig, you're looking up the name "orig" via the symbol table, so the redef function needs to be altering the symbol table, so that it can point that name to a different bit of code. Globrefs are basically pointers to little bits of symbol table, so that's what you need to pass to ReDef::redef.
As an analogy, imagine that when you want to know the date of the Battle of Lewes, your procedure is to go to the library, look in the catalogue for the shelf address of a book on 13th century English battles, go to that shelf, and look up the date... voila 14 May 1264! Now, imagine I want to feed you altered information. Simply defining a new coderef would be like putting a new book on the shelf: it won't trick you because the catalogue is still pointing you at the old book. We need to alter the catalogue too.
UPDATE
You can make this a little prettier using prototypes. Prototypes are not usually recommended, but this seems to be a non-evil use for them...
use strict;
use warnings;
sub ReDef::redef (*) {
my $ref = shift;
no warnings qw(redefine);
*$ref = sub { print "Redefined!\n" };
}
sub orig { print "Original!\n" }
orig;
ReDef::redef *orig; # don't need the backslash any more
orig;
This works for me:
use v5.16;
use strict;
use warnings;
package Redef;
sub redef {
my $ref = shift;
${$ref} = sub { say "Redefined!"; }
}
package main;
my $orig = sub { say "Original!"; };
Redef::redef(\$orig);
$orig->(); # Redefined!
Although it’s just a result of trial and error, I’d be happy to see better answers.
What maybe got you confused is the typeglob operator, *. In Perl you dereference using a sigil (${$scalar_ref}, #{$array_ref}) and the * operator is used for symbol table tricks – which could also be used in your case, see the answer by #tobyink.

How to replace package name with a variable when using strictures

I have two Perl packages: pack_hash and pack_run
package pack_hash;
$VERSION = '1.00';
#ISA = qw( Exporter );
#EXPORT_OK = qw( %hashInfo );
$hashInfo{abc} = ['a', 'b', 'c'];
1;
package pack_run;
use stricts;
use warnings;
use Data::Dumper;
use pack_hash qw( %hashInfo );
somethingDoing();
sub somethingDoing {
my $var1 = \%pack_hash::hashInfo; # getting the hash reference
print Dumper($var1);
...
...
}
1;
Can anyone please let me know, whether it is possible to replace the name of the hash-package (pack_hash), by using any variable, like:
my $pakVar = "pack_hash";
my $var1 = \%$pakVar::hashInfo;
I, know it is WRONG/NOT_CORRECT, but I want this kind of symbolic ref transformation, when I'm using strictures.
I also wanted to know, whether it is possible to do the thing with eval. But I want a final variable, here $var1, which will refer the particular hash (hashInfo);
No, that is not possible. But this is:
use strict;
use warnings;
use Symbol qw<qualify_to_ref>;
my $pakVar = 'pack_hash';
my $var1 = *{ qualify_to_ref( 'hashInfo', $pakVar ) }{HASH};
qualify_to_ref takes the name of a package variable and the package name and returns a GLOB reference pointer, then you just access the HASH slot of the GLOB. You can also do it this way:
my $var1 = \%{ qualify_to_ref( 'hashInfo', $pakVar ) };
But it is just as easy to turn off strict in a very tight do as well;
my $var1
= do {
no strict;
\%{ $pakVar . '::hashInfo' };
};
I understand that some coding cultures consider turning off strict or warnings as "cheating". I know that I've had code review questions about turning off one class of warning in a small block like this. I knew which warnings I was going to get, so I didn't need it. The reviewer didn't see it this way.
For this reason some veteran Perl-ers think nothing about turning off strict. But if you can't because it makes the natives restless--you can use Symbol. However, some shops have rules against package variables, so it never becomes an issue.
If you have a class method that returns a reference to the hash:
package pack_hash;
use strict;
use warnings;
our %hashInfo;
$hashInfo{abc} = ['a', 'b', 'c'];
sub hashInfo { \%hashInfo }
then you can easily get the reference:
use strict;
use warnings;
my $pakVar = 'pack_hash';
my $hashInfo = $pakVar->hashInfo();
print #{ $hashInfo->{'abc'} };

Accessing class variables using a variable with the class name in perl

I'm wondering how I would go about doing this:
package Something;
our $secret = "blah";
sub get_secret {
my ($class) = #_;
return; # I want to return the secret variable here
}
Now when I go
print Something->get_secret();
I want it to print blah. Now before you tell me to just use $secret, I want to make sure that if a derived class uses Something as base, and I call get_secret I should get that class' secret.
How do you reference the package variable using $class? I know I can use eval but is there more elegant solution?
Is $secret supposed to be modifiable within the package? If not, you can get rid of the variable and instead just have a class method return the value. Classes that want to have a different secret would then override the method, instead of changing the value of the secret. E.g.:
package Something;
use warnings; use strict;
use constant get_secret => 'blah';
package SomethingElse;
use warnings; use strict;
use base 'Something';
use constant get_secret => 'meh';
package SomethingOther;
use warnings; use strict;
use base 'Something';
package main;
use warnings; use strict;
print SomethingElse->get_secret, "\n";
print SomethingOther->get_secret, "\n";
Otherwise, perltooc contains useful techniques to fit a variety of scenarios. perltooc points to Class::Data::Inheritable which looks like it would fit your needs.
You can use a symbolic reference:
no strict 'refs';
return ${"${class}::secret"};

Why does my Perl program complain about needing explicit package names?

I have a module Routines.pm:
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my %predecessor_matrix = shift;
my %shortestpath_matrix = shift;
...
}
From another script I call the sub in the module, passing in arguments which happen to have the same name:
use Routines;
use strict;
my %predecessor_matrix = ();
my %shortestpath_matrix =();
&Routines::load_shortest_path_matrices($predecessor_matrix, $shortestpath_matrix);
However, this doesn't compile and I get
Global symbol "$predecessor_matrix" requires explicit package name
type of errors. Is it not possible to give the same name to variables in different scopes like this in Perl? (I'm from a C background)
$predecessor_matrix is a scalar and %predecessor_matrix is a hash. Different types in Perl (scalar, array, hash, function, and filehandle) have different entries in the symbol table, and, therefore, can have the same name.
Also, you have a problem in your function. It expects to be able to get two hashes from #_, but a hash in list context (such as in the argument list of a function) yields a list of key value pairs. So, both %predecessor_matrix and %shortestpath_matrix will wind up in the %predecessor_matrix of the function. What you need to do here is to use references:
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my $predecessor_matrix = shift;
my $shortestpath_matrix = shift;
$predecessor_matrix->{key} = "value";
...
}
and
use Routines;
use strict;
my %predecessor_matrix;
my %shortestpath_matrix;
Routines::load_shortest_path_matrices(
\%predecessor_matrix,
\%shortestpath_matrix
);
However, passing in structures to load as arguments is more C-like than Perl-like. Perl can return more than one value, so it is more common to see code like:
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my %predecessor_matrix;
my %shortestpath_matrix;
...
return \%predecessor_matrix, \%shortestpath_matrix;
}
and
use Routines;
use strict;
my ($predecessor_matrix, $shortestpath_matrix) =
Routines::load_shortest_path_matrices();
for my $key (keys %$predecessor_matrix) {
print "$key => $predecessor_matrix->{$key}\n";
}
you are declaring the hash %predecessor_matrix but are trying to pass the scalar $predecessor_matrix. The hash exists, the scalar doesn't.
Maybe you want to pass references to the hashes?
Routines::load_shortest_path_matrices(\%predecessor_matrix, \%shortestpath_matrix);
Here's another way to code it:
use strict;
use warnings;
use Routines;
my $predecessor_matrix = {};
my $shortestpath_matrix ={};
Routines::load_shortest_path_matrices( $predecessor_matrix
, $shortestpath_matrix
);
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my $predecessor_matrix = shift;
my $shortestpath_matrix = shift;
...
}
you can access the contents of the hashes like this
my $foobar=$shortestpath_matrix->{FOOBAR};