I have a Perl program and packages Worker and Log.
The Worker does almost all calculations, and I want to pass an object by reference to the Worker subroutine, as well as some other parameters (scalar and an array). I have seen examples like this and this.
They handle this by putting #_ in subs, then manipulating the object. I also found a way to manipulate them by using the index, like #{$_[i]}. Problem is, when I try the code like so, I get an error:
Can't call method "write" on unblessed reference at ...
Code snippets below.
Main:
use strict;
use warnings;
use Log;
use Worker;
my $log = Log->new();
my $worker = Worker->new();
my $scalar = "SomeURLhere";
my #array = ('red','blue','white');
# I do some stuff with $log object
#...
# Now I want to pass data to the Worker
$worker->subFromWorker($scalar, \$log, \#array);
Worker:
use strict;
use warnings;
package Worker;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub subFromWorker{
my ($self) = shift;
my $scalar = $_[0];
#my ($log) = $_[1];
my #array = #{$_[2]};
foreach my $item (#array){
print $item;
}
$_[1]->write("The items from url $scalar are printed.");
#Same thing happens if I use $log here
}
In C#, this is handled in a different way - you can send a parameter to a method by value or by reference, and then do what you want in a specialized method (method is pre-written to handle parameters by reference or value). I thought that in Perl sending using \parameter will send the reference.
Objects are references. References are scalar values.
If you want to pass arrays or hashes into a subroutine then you usually want to pass references to them - because Perl parameter passing works far better with scalar values.
But $log is already a reference to your object. Therefore you don't need to take a reference to it. You end up passing a reference to a reference. So when you copy that parameter into $log inside your subroutine you have an extra, unnecessary, level of references.
The fix is to just pass the $log scalar into the subroutine.
$worker->subFromWorker($scalar, $log, \#array); # $log, not \$log
Everything else will then work fine.
You have read about the issues that prevent your program from working, but there are a few other things you should be aware of
Perl lexical identifiers and subroutine/method names consist of alphanumerics and underscore. Capital letters are reserved for global identifiers, such as package names like Worker and Log.
Packages that you use or require should end with the statement 1; so as to return a true value when they are imported, otherwise your program may fail to compile.
If a subroutine that you are writing happens to be a method, then it is clearest to start it by shifting off the $self parameter and making a copy of the rest:
my $self = shift;
my ($p1, $p2, $p3) = #_;
It is rare to use elements of #_ directly unless you're desperate for the minimal speed bonus
It is usually best to work directly with an array reference rather than copying the array, especially if it may be large.
Here is how I would code your program and associated modules:
program.pl
use strict;
use warnings;
use Worker;
use Log;
my $log = Log->new;
my $worker = Worker->new;
my $scalar = 'SomeURLhere';
my #array = qw/ red blue white /;
$worker->worker_method($scalar, $log, \#array);
Worker.pm
use strict;
use warnings;
package Worker;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub worker_method {
my $self = shift;
my ($scalar, $log, $array) = #_;
foreach my $item (#$array) {
print $item, "\n";
}
$log->write("The items from URL $scalar are printed.");
}
1;
Log.pm
use strict;
use warnings;
package Log;
sub new {
my $class = shift;
bless {}, $class;
}
sub write {
my $self = shift;
my ($text) = #_;
print "Logging: $text\n"
}
1;
Output
red
blue
white
Logging: The items from URL SomeURLhere are printed.
A more common pattern is to use List assignment to unpack #_ into multiple variables all at once:
sub subFromWorker {
my ($self, $scalar, $log_ref, $array) = #_;
...
}
In reference to your specific problem:
my $log = Log->new();
$log is already a reference to your object, using \$log creates a reference to that reference which is not probably not what you want. You can handle this two ways:
only pass $log:
$worker->subFromWorker($scalar, $log, \#array);
dereference $log in subFromWorker before calling functions on it:
$$log_ref->write('...');
Related
How can I catch access to member variables?
$Class1->{Class2}
If the Class2 field doesn't exist, is is possible to catch this from an internal function?
You can, but you probably shouldn't. The problem here is - if you access a variable within a class directly... then you just can. You can prevent this with a couple of workarounds - and this is where things like Moose come in.
And there's a couple of slightly hacky tricks like inside-out objects (which I think aren't common practice any more - Perl Best Practice advocated them some years back) or using anonymous hashes to hold state.
But failing that - why not use an accessor, and auto-generate one using 'AUTOLOAD'.
#!/usr/bin/env perl
package MyClass;
use strict;
use warnings;
use vars '$AUTOLOAD';
sub AUTOLOAD {
my ( $self ) = #_;
my $subname = $AUTOLOAD =~ s/.*:://r;
if ( $self -> {$subname} ) {
return $self -> {$subname};
}
warn "Sub called $subname was called\n";
return "$subname";
}
sub new {
my ( $class ) = #_;
my $self = {};
bless $self, $class;
}
package main;
use strict;
use warnings;
my $object = MyClass -> new;
$object -> {var} = "fleeg";
print "Undef fiddle was: ", $object -> fiddle,"\n";
print "But 'var' was: ", $object -> var,"\n";
This has the same problem, in that changing method names might cause things to break. However it has the advantage that you can handle 'invalid' method calls however you like.
But really - explicit 'get' and 'set' methods are better choices for most use-cases.
You do this by providing proper getter/setter methods that wrap around your class/instance variables. The internals should never be accessed directly, particularly from outside of the class itself (it's wise to not do so within the class either, except for the actual method that maintains that specific attribute. Here's a very basic example:
use warnings;
use strict;
package A;
sub new {
my ($class, %args) = #_;
my $self = bless {}, $class;
$self->x($args{x});
$self->y($args{y});
return $self;
}
sub x {
my ($self, $x) = #_;
$self->{x} = $x if defined $x;
return $self->{x} // 1;
}
sub y {
my ($self, $y) = #_;
$self->{y} = $y if defined $y;
return $self->{y} // 2;
}
package main;
my $obj = A->new(x => 5, y => 3);
print $obj->x ."\n";
print $obj->y ."\n";
Now, you could just as easily do print $obj->{x}, but that's where your problem is. What happens when the code is much more complicated than this, and for some reason you want to change the x attribute name to foo, but retain the x() method? $obj->{x} will now be undef as its never set.
Always use the provided methods for accessing attributes of a class/object. Encapsulation such as this is a staple of OO programming.
In perl, a class "Lamba" implements a method called "process".
use Lambda;
my $omega = Lambda->new();
$omega->process();
in the process method, how can we get the name of it's invocant?
package Lambda;
use strict;
sub new {
my $class = shift;
my $self = {};
bless ($self, $class);
return $self;
}
sub process {
my $self = shift;
my $invocant;
#
# ??? what is the variable name of my caller ???
#
# ie. how to set $invocant = 'omega';
#
return $self;
}
Update
I've just realised that you want the name of the variable that was used to call the process method. You can't do that without a source filter, because there may be several names all referring to the same object, like this
my $omega = Lambda->new;
my $aa = $omega;
my $bb = $omega;
$aa->process;
and there is quite sensibly no way to get hold of the name actually used to call the method
This is an X Y problem, and is comparable to asking how to use data strings to name a variable. Variable identifiers are purely for the consumption of the programmer, and if you think your program needs to know them then you have a design problem. If you explain exactly what it is that you want to achieve via this mechanism then I am sure we could help you better
Original solution
I've left this here in cased someone arrives at this page looking for a way to discover the name of the calling code
You can use the caller function
A call without parameters like caller() will return the package name, source file name, and line number where the current call was made
You get get more detailed information by adding a parameter that represents the depth on the call stack that you want to examine, so caller(0) will return information about the current subroutine, while the values from caller(1) will be about the calling subroutine
If we change your main code to use a subroutine to call the method, then we can write this
Lambda.pm
package Lambda;
use strict;
use warnings;
sub new {
bless {}, shift;
}
sub process {
my $self = shift;
#
# ??? what is the variable name of my caller ???
#
# ie. how to set $invocant = 'omega';
#
my $calling_sub = (caller(1))[3];
print "Called by $calling_sub\n";
return $self;
}
1;
main.pl
use strict;
use warnings 'all';
use Lambda;
mysub();
sub mysub {
my $omega = Lambda->new;
$omega->process;
}
output
Called by main::mysub
The caller function returns information about the calling subroutine/sourcecode line:
sub process {
my $self = shift;
print join(', ',caller(0)); # Some of these values will be undef!
}
The manual page shows this example:
($package, $filename, $line, $subroutine, $hasargs,
$wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
= caller($i);
Increase $i to walk further through the stacktrace (reverse list of callers):
my $i = 0;
while (my #ci = caller($i++)) {
print "$i. ".$ci[1].':'.$ci[2]."\n";
}
Starts with $i=0 and increases $i after passing it to the caller() function. Prints a stacktrace back to the line of the script starting the current process.
I am new in OO perl, below is the code i have written for my learning purpose but unfortunately i am not getting correct output :
#Calculation.pm
package Calculation;
sub new
{
my $class =shift;
# my $number =shift;
my $self ={};
bless ($self,$class);
return $self;
}
sub add
{
my $val_01=shift;
my $val_02=shift;
my $total = $val_01+$val_02;
return($total);
}
1;
#Test.pl
#!/usr/bin/perl
use warnings;
use strict;
use Calculation;
my $obj = Calculation->new();
my $result =$obj->add(1,2);
print"$result\n";
$result is returning a random values.
When you call $obj->add(1,2) your add sub gets 3 arguments: $obj, 1, 2. You're shifting and adding the first 2 arguments, $obj and 1. When $obj is converted to a number for addition, its memory address is used. Add 1 to that and you get a not-quite-random-but-certainly-ugly number.
You just need to add another shift at the top of sub add.
As has been pointed out, you aren't taking account of the first parameter that is passed implicitly to the method call, usually assigned to $self.
You can also omit some of the intermediate variables to simplifiy, and it is common practice to omit the return statement when the value to be returned is the last statement in the subroutine.
This variant of your code works fine
Calculation.pm
use strict;
use warnings;
package Calculation;
sub new {
my $class = shift;
bless {}, $class;
}
sub add {
my $self = shift;
my ($val_01, $val_02) = #_;
$val_01 + $val_02;
}
1;
Test.pl
use strict;
use warnings;
use Calculation;
my $obj = Calculation->new;
my $result = $obj->add(1, 2);
print "$result\n";
output
3
Is it possible to get all valid methods for a particular Perl class?
I am trying to manipulate the symbol table of a class and get all of its methods. I found I can separate out the subroutines from the non-subroutines via the $obj->can($method), but that doesn't do exactly what I think it does.
The following returns:
subroutine, Property, croak, Group, confess, carp, File
However, subroutine isn't a method, (just a subroutine), and croak, confess, and carp were all imported into my package.
What I really want to print out is:
Property,Group, File
But I'll take:
subroutine, Property,Group, File
Below is my program:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
my $sections = Section_group->new;
say join ", ", $sections->Sections;
package Section_group;
use Carp;
sub new {
return bless {}, shift;
}
sub Add {
my $self = shift;
my $section = shift;
}
sub Sections {
my $self = shift;
my #sections;
for my $symbol ( keys %Section_group:: ) {
next if $symbol eq "new"; # This is a constructor
next if $symbol eq "Add"; # Not interested in this method
next if $symbol eq "Sections"; # This is it's own method
push #sections, $symbol if $self->can($symbol);
}
return wantarray ? #sections : \#sections;
}
sub subroutine {
my $param1 = shift;
my $param2 = shift;
}
sub Group {
my $self = shift;
my $section = shift;
}
sub File {
my $self = shift;
my $section = shift;
}
sub Property {
my $self = shift;
my $section = shift;
}
This is fairly trivial. We only want to keep those sub names that were originally defined in our package. Every CV (code value) has a pointer to the package where it was defined. Thanks to B, we can examine that:
use B ();
...
if (my $coderef = $self->can($symbol)) {
my $cv = B::svref_2object $coderef;
push #sections, $symbol if $cv->STASH->NAME eq __PACKAGE__;
}
# Output as wanted
That is, we perform introspection using svref_2object. This returns a Perl object representing an internal perl data structure.
If we look into a coderef, we get a B::CV object, which represents the internal CV. The STASH field in a CV points to the Stash where it was defined. As you know, a Stash is just a special hash (internally represented as a HV), so $cv->STASH returns a B::HV. The NAME field of a HV contains the fully qualified package name of the Stash if the HV is a Stash, and not a regular hash.
Now we have all the info we need, and can compare the wanted package name to the name of the stash of the coderef.
Of course, this is simplified, and you will want to recurse through #ISA for general classes.
Nobody likes polluted namespaces. Thankfully, there are modules that remove foreign symbols from the Stash, e.g. namespace::clean. This is no problem when the CVs of all subs you are calling are known at compile time.
What are you trying to do? Why does it matter how a class defined or implements a method it responds to?
Perl is a dynamic language, so that means that methods don't have to exist at all. With AUTOLOAD, a method might be perfectly fine and callable, but never show up in the symbol table. A good interface would make can work in those cases, but there might be cases where a class or an object decides to respond to that with false.
The Package::Stash module can help you find defined subroutines in a particular namespace, but as you say, they might not be defined in the same file. The methods in a class might come from an inherited class. If you care about where they come from, you're probably doing it wrong.
I'm trying to add some functionality to our code base by using tied scalars.
We have a function which is specified to return scalars. I thought I could add some features to the system by tie-ing these scalars before returning them, but it looks like the FETCH method is called just before the return, which results in an untied scalar being returned.
Is there any way around this?
I really want to keep the subroutine's interface (returning scalars) intact if it's at all possible.
use strict;
use warnings;
main();
sub GetThing{
my $thing;
tie $thing, 'mything', #_;
return $thing;
}
sub main {
my %m;
$m{pre} = GetThing('Fred');
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
require Tie::Scalar;
my #ISA = qw(Tie::StdScalar);
sub TIESCALAR {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
sub FETCH {
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
}
Desired output:
1
ACCESS ALERT!
NAME: 'Fred'
2
ACCESS ALERT!
NAME: 'Fred'
3
I can get the desired output by returning a reference, and dereferencing on each access, but that ruins our established interface, and makes it more confusing for our users.
--Buck
As DVK said, tie applies to containers, so isn't useful for returned values.
For that, you use overloading. An example (not all the possible overloaded operations are supplied; see http://perldoc.perl.org/overload.html#Minimal-set-of-overloaded-operations):
use strict;
use warnings;
main();
sub GetThing{
my $thing;
$thing = "mything"->new(#_);
return $thing;
}
sub main {
my %m;
$m{pre} = GetThing('Fred');
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
use overload 'fallback' => 1, '""' => 'FETCH';
sub new {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
sub FETCH {
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
}
As mentioned in other answers, tie applies to containers, and not to values, so there is no way to assign a tied variable to another variable and retain the tied properties.
Since assignment is out, you need to pass the container into the GetThing routine. You can do this by reference as follows:
use strict;
use warnings;
main();
sub GetThing{
tie ${$_[1]}, 'mything', $_[0];
}
sub main {
my %m;
GetThing('Fred' => \$m{pre});
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
require Tie::Scalar;
my #ISA = qw(Tie::StdScalar);
sub TIESCALAR {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
sub FETCH {
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
}
which produces the correct output.
However, if you want to retain the assignment, you will need to use overloading, which applies to values (actually to objects, but they themselves are values). Without more detail on your intended purpose it is hard to give a complete answer, but this will meet your stated requirements:
use strict;
use warnings;
main();
sub GetThing{
return mything->new( shift );
}
sub main {
my %m;
$m{pre} = GetThing('Fred');
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
sub new {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
use overload '""' => sub { # '""' means to overload stringification
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
};
Both ties and overloads can get complicated, so read through all of the documentation if anything is not clear.
First, the exact method of doing what you are proposing seems technically impossible:
Tied variables have the tie attached to the variable itself, not to its value.
In Perl, subroutine's return values are returned by value, meaning you take the value passed to return, access it (in you case, accessing the tied variable and calling FETCH in the process) - and then copy that value! Which means that what the caller gets is a scalar VALUE, not a scalar variable (tied or untied).
Your confusion, in short, seems to stem from mixing together variables (locations in program's symbol table) and values stored in those variables.
Second, you were somewhat unclear as to what exactly you are trying to achieve, so it's hard to propose how to achieve what you want. But assuming, based on your description, that you wanted to call some method upon subroutine's return (possibly passing it the return value), you CAN do that.
To do so, you need to employ what fancy people call aspect programming. The politically (and technically) correct way of doing it in Perl is by using Moose.
However, you can DIY it, by basically replacing the original method with a wrapper method.
The exact mechanics of both Moose and DIY approaches can be seen in the first two answers to the following SO question, so I won't copy/paste them here, hope you don't mind:
Simulating aspects of static-typing in a duck-typed language
If you're feeling adventurous, you could also use the Scalar::Defer module which provides a general-purpose mechanism for a scalar variable to compute a value lazily, either once or on each access.