Difference between double colon and arrow in perl - perl

If it is duplicate, say so. I Have not found it, only for PHP but for Perl. So If I can write full name of e.g. Class::sub() or $Class::scalar, I can write Class->sub or $Class->scalar(in case I have used or required the Class), what is the main difference in perl?
The problem is:
Class Animal.pm:
#!/usr/bin/perl -w
package Animal;
our $VERSION = '0.01';
sub speak {
my $class = shift;
print "a $class goes ", $class->sound;
}
sub sound{
die "You have to defined sound() in a subclass";
}
Then Class Horse.pm:
#!/usr/bin/perl -w
package Horse;
use Animal;
our #ISA = qw[Animal];
our $VERSION = '0.01';
sub sound { 'neight' }
1
And if I, in main program do this:
#!/usr/bin/perl -w
BEGIN{ unshift #INC, 'dirWithModules' }
use Horse; use Animal;use Cow;
Animal::speak('Horse');
output---->"a Horse goes neight"
BUT IF I OD
#!/usr/bin/perl -w
BEGIN{ unshift #INC, 'dirWithModules' }
use Horse; use Animal;use Cow;
Animal->speak('Horse')
output--->"You have to defined sound() in a subclass at Animal.pm"
So my question is, If I reference my method from class Horse.pm iherited sub speak from Animal.pm with ::, double colon, the NO PROBLEM - it will print the sound. However if I try to reference the sub with -> arrow, The $class is not inherited - that is, $class is Animal.pm itself, but not as parameter sent ('Horse'). So In what is :: and -> different?

Foo->bar() is a method call.
It will use inheritance if necessary.
It will pass the invocant (the left side of ->) as the first argument. As such, bar should be written as follows:
# Class method (Foo->bar)
sub bar {
my ($class, ...) = #_;
}
or
# Object method (my $foo = Foo->new; $foo->bar)
sub bar {
my ($self, ...) = #_;
}
Foo::bar() is a sub call.
It won't use inheritance.

Related

Getting wrong argument value when trying to call a subroutine using PackageName::ModuleName->subroutine("xyz")in perl

When trying to call a subroutine (defined in a user defined module) in other perl file, getting wrong argument value
#moduleName.pm
package PackageName::moduleName;
use strict;
use warnings;
use base 'Exporter';
sub callMe{
my($readArg)=(#_);
print $readArg;
}
#test.pl
use strict;
use warnings;
use FindBin; # locate this script
use lib 'path to parent directory'; # use the parent directory
use PackageName::moduleName;
if( my $temp=PackageName::moduleName->callMe("test")){
print" True : $temp\n";
}
The function prints value of $temp as : PackageName::moduleName
Not able to figure out why.
P.S. I have to maintain same convention while calling the subroutine
You are calling a function as a class method with Foo::Bar->frobnicate(#args). In that case, Perl will do the following things because of the arrow ->:
check what's on the left of the arrow
if it's blessed, find the package (e.g. $q is package CGI)
if it's not blessed, assume it's a package (e.g. Foo::Bar)
within that package namespace, find a sub with the name on the right of the arrow (e.g. frobnicate)
call that sub and pass what's on the left of the arrow as the first argument
Now it looks like this:
Foo::Bar::frobnicate('Foo::Bar', #args);
In frobnicate, you have to deal with that:
sub frobnicate {
my ($class, #args) = #_;
# ...
}
That's typically done in a new, which is the most likely use of a class method.
If you don't want to deal with it, call the sub directly in its namespace, and not with the arrow notation.
my $rv = Foo::Bar::frobnicate(#args);
Because of the way you're calling it via ->.
When you do this, perl passes extra arguments, so you can make a constructor (new).
E.g.
my $thing = Package::Module -> new();
The first argument passed is the class, so you can use that for a bless. See:
perlootut
E.g.
sub new {
my ( $class, #args ) = #_;
my $self = {};
bless ( $self, $class );
}
This also applies when you call an instantiated object:
$thing -> do_something();
It passes a reference to $self as the first argument.
sub do_something {
my ( $self, #args ) = #_;
print "Got args of #args\n";
$self -> {firstarg} = shift ( #args );
}
If you want to do that, try instead:
PackageName::ModuleName::callMe("test");

Perl: How to make sure overridden method is called when accessed from within the base class

I have a base class which calls a method which is overridden in a child class, in Perl. Currently, it still calls the base class version of the method, but I want it to call the base if there is one. Here is a simplified rendition of my code:
package Test;
use strict;
use warnings;
sub Main
{
my $self = shift;
return $self->SomeFunc();
}
sub SomeFunc
{
my $self = shift;
#...
return 1;
}
package Test2;
use strict;
use warnings;
use base qw(Test);
sub SomeFunc
{
my $self = shift;
#...
return 0;
}
package main;
use Test2;
my $test = new Test2();
print $test->Main();
and I am getting a 1 when I run this!
PS my apologies, I'm not used to creating examples in working perl code, please forgive the obvious errors.
The problem would be in your constructor, but you don't have one so your code doesn't even do what you say it does
You have probably written something like
sub new {
bless {};
}
which blesses an empty hash into the current package. Instead you need to take the class name from the first parameter passed to the constructor, like this
You should also avoid using capital letters in your lexical identifiers as they are reserved for global identifiers like package names. If you must use CamelCase then at least makeSureTheFirstLetterIsLowerCase. The standard for both Perl and Python is to use the much_clearer_snake_case
Test.pm
package Test;
use strict;
use warnings;
sub new {
my $class = shift;
bless {}, $class;
}
sub main {
my $self = shift;
$self->some_func();
}
sub some_func {
my $self = shift;
'Test::some_func';
}
Test2.pm
package Test2;
use strict;
use warnings;
use parent 'Test';
sub some_func {
my $self = shift;
'Test2::some_func';
}
main.pl
use strict;
use warnings;
my $test = Test->new;
print $test->main, "\n";
$test = Test2->new;
print $test->main, "\n";
output
Test::some_func
Test2::some_func
new doesn't mean anything in perl unless you make a function with that method name.
You need to bless an object
You can either directly bless an object
my $test = { };
bless $test, "Test2";
or make a new method that does the blessing for you:
sub new{
my $class = shift;
my $test = { };
bless $test, $class;
}

Do something after sub foo in Perl?

after foo => sub{
...
}
I just stumble upon code like above, which is called after sub foo finishes,
how does that work?
It seems it's not built-in feature of Perl,right?
It's one of the Moose method modifiers.
Method modifiers can be used to add behavior to methods without modifying the definition of those methods.
Out of curiosity, I've tried to do it myself, and got code that works to some extent (no list context, no corner cases etc.).
Perl allows for horrible things.
% perl -wle 'use After; sub foo { $_[0] * 2};
after foo => sub { print $_[0] }; foo(5); foo(6);'
10
12
Here's After.pm. Please don't ever use it.
use warnings;
use strict;
package After;
# make after() available after 'use After;'
use Exporter;
BEGIN {
our #ISA = qw(Exporter);
our #EXPORT = qw(after);
};
# prototype: bareword + sub
sub after (*&) {
my ($name, $code) = #_;
my $caller = caller; # get calling package
# fetch old sub named "name"
# note $oldcode = *{...} is not ehough
my $oldcode;
{
no strict 'refs';
$oldcode = \&{$caller."::".$name};
};
# defined new sub
my $newcode = sub {
my $ret = $oldcode->(#_); # call old sub as is
$code->($ret); # call the after sub
return $ret; # ignore aftersub's ret val
};
# plant new sub into the calling package
# avoid redefinition warnings
{
no strict 'refs';
no warnings 'redefine';
*{$caller."::".$name} = $newcode;
};
};
1;
It is not a builtin feature as others have already stated. For programs that do not use Moose, you can use Class::Method::Modifiers to get these modifiers.
If after is a predeclared subroutine, it would mean that you call that sub, with foo and an anonymous sub as arguments. It does seem a bit odd, though.
=> is equivalent to a comma, so assuming after is a sub, it would mean this:
after('foo', sub { ... });

How does an object access the symbol table for the current package?

How could I access the symbol table for the current package an object was instantiated in? For example, I have something like this:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
If in the implementation of do_your_job I use __PACKAGE__, it will search in the MyModule package. How could I make it look in the right package?
EDIT:I'll try to make this clearer. Suppose I have the following code:
package MyMod;
sub new {
return bless {},$_[0]
}
sub do_your_job {
my $self = shift;
# of course find_package_of is fictional here
# just for this example's sake, $pkg should be main
my $pkg = find_package_of($self);
if(defined &{ $pkg . '::run_me' }) {
# the function exists, call it.
}
}
package main;
sub run_me {
print "x should run me.\n";
}
my $x = MyMod->new;
# this should find the run_me sub in the current package and invoke it.
$x->do_your_job;
Now, $x should somehow notice that main is the current package, and search it's symbol table. I tried using Scalar::Util's blessed , but it still gave me MyModule instead of main. Hopefully, this is a bit clearer now.
You just want caller
caller tells you the package from which it was called. (Here I added some standard perl.)
use Symbol qw<qualify_to_ref>;
#...
my $pkg = caller;
my $symb = qualify_to_ref( 'run_me', $pkg );
my $run_me = *{$symb}{CODE};
$run_me->() if defined $run_me;
To look it up and see if it's defined and then look it up to call it would duplicate it as standard perl doesn't do Common Subexpression Elimination, so you might as well 1) retrieve it, and 2) check definedness of the slot, and 3) run it if it is defined.
Now if you create an object in one package and use it in another, that's not going to be too much help. You would probably need to add an additional field like 'owning_package' in the constructor.
package MyMod;
#...
sub new {
#...
$self->{owning_package} = caller || 'main';
#...
}
Now $x->{owning_package} will contain 'main'.
See perldoc -f caller:
#!/usr/bin/perl
package A;
use strict; use warnings;
sub do_your_job {
my ($self) = #_;
my ($pkg) = caller;
if ( my $sub = $pkg->can('run_me') ) {
$sub->();
}
}
package B;
use strict; use warnings;
sub test {
A->do_your_job;
}
sub run_me {
print "No, you can't!\n";
}
package main;
use strict; use warnings;
B->test;
Output:
C:\Temp> h
No, you can't!

How do I inherit subroutines in Perl with 'use base'?

How do I apply 'use base' in Perl to inherit subs from some base module?
I'm used to C++ inheritance mechanics, and all the sites I googled for this caused more confusion then help. I want to do something like the following:
#! /usr/bin/perl
#The base class to inherit from
use strict;
use warnings;
package 'TestBase';
#-------------------------------
sub tbSub
{
my ($self, $parm) = #_;
print "\nTestBase: $parm\n";
}
1;
.
#! /usr/bin/perl
#The descendent class
use strict;
use warnings;
use base qw(TestBase);
sub main;
sub mySub;
#-------------------------------
#Entry point...
main();
#---code------------------------
sub main
{
mySub(1);
tbSub(2);
mySub(3);
}
#-------------------------------
sub mySub
{
my $parm = shift;
print "\nTester: $parm\n";
}
Perl complains/cannot find tbSub.
The C++ mechnics aren't much different than the Perl mechanics: To use inheritance, you need two classes: the base class and the inheriting class. But you don't have any descendent class.
You are also lacking a constructor. Unlike C++, Perl will not provide a default constructor for you.
Your base class contains a bad syntax error, so I guess you didn't try the code before posting.
Finally, as tsee already observed, you will have to let Perl know whether you want a function call or a method call.
What you really want would look something like this:
my $foo = TestDescendent->new();
$foo->main();
package TestBase;
sub new {
my $class = shift;
return bless {}, $class;
}
sub tbSub
{
my ($self, $parm) = #_;
print "\nTestBase: $parm\n";
}
package TestDescendent;
use base 'TestBase';
sub main {
my $self = shift;
$self->mySub( 1 );
$self->tbSub( 2 );
$self->mySub( 3 );
}
sub mySub
{
my $self = shift;
my $parm = shift;
print "\nTester: $parm\n";
}
1;
You should have a look at using Moose which is a postmodern object system for Perl5. You will probably find it a lot easier to grasp than using standard Perl OO semantics... especially when coming from another OO language.
Here's a Moose version of your question....
package TestBase;
use Moose;
sub tbSub {
my ($self, $parm) = #_;
print "\nTestBase: $parm\n";
}
package TestDescendent;
use Moose;
extends 'TestBase';
sub main {
my $self = shift;
$self->mySub( 1 );
$self->tbSub( 2 );
$self->mySub( 3 );
}
sub mySub {
my ($self, $parm) = #_;
print "\nTester: $parm\n";
}
package main;
my $foo = TestDescendent->new();
$foo->main
The differences are....
Constructor automatically created for you &
Inheritance defined by "extends" command instead of "use base".
So this example only covers the tip of the Moose iceberg ;-)
As a sidenote, there is little good reason to use base rather than the newer use parent.
It seems to me, you are mixing up two things here: Object-Oriented and Procedural Perl. Perl OO is kind of "different" (as in not mainstream but workable).
Your TestBase.pm module seems to expect to be run as a Perl object (Perl oo-style), but your Perl script wants to access it as "normal" module. Perl doesn't work the way C++ does (as you realised) so you would have to construct your code differently. See Damian Conway's books for explanations (and smarter code than mine below).
Procedural:
#! /usr/bin/perl
#The module to inherit from
package TestBase;
use strict;
use warnings;
use Exporter ();
our #ISA = qw (Exporter);
our #EXPORT = qw (tbSub);
#-------------------------------
sub tbSub
{
my ($parm) = #_;
print "\nTestBase: $parm\n";
}
1;
.
#! /usr/bin/perl
#The descendent class
use strict;
use warnings;
use TestBase;
sub main;
sub mySub;
#-------------------------------
#Entry point...
main();
#---code------------------------
sub main
{
mySub(1);
tbSub(2);
mySub(3);
}
#-------------------------------
sub mySub
{
my $parm = shift;
print "\nTester: $parm\n";
}
Perl OO
#! /usr/bin/perl
#The base class to inherit from
package TestBase;
use strict;
use warnings;
#-------------------------------
sub new { my $s={ };
return bless $s;
}
sub tbSub
{
my ($self,$parm) = #_;
print "\nTestBase: $parm\n";
}
1;
.
#! /usr/bin/perl
#The descendent class
use strict;
use warnings;
use TestBase;
sub main;
sub mySub;
#-------------------------------
#Entry point...
main();
#---code------------------------
sub main
{
my $tb = TestBase->new();
mySub(1);
$tb->tbSub(2);
mySub(3);
}
#-------------------------------
sub mySub
{
my $parm = shift;
print "\nTester: $parm\n";
}
Perl's inheritance inherits methods, not functions. That means you will have to call
main->tbSub(2);
However, what you really want is to inherit the method into a proper class:
package Derived;
use base "TestBase";
package main;
Derived->somemethod("foo");
Calling methods in the current package as functions won't pass in the $self or "this" object nor the class name magically. Internally,
Class->somemethod("foo")
essentially ends up being called as
Class::somemethod("Class", "foo")
internally. Of course, this assumes Class has a subroutine/method named "somemethod". If not, the superclasses of Class will be checked and if those don't have a method "somemethod" either, you'll get a fatal error. (Same logic applies for $obj->method("foo").)
OO syntax uses the -> operator to separate the message and arguments from the receiver of the message. A short illustration below.
You->do_something( #params );
OR
$you->do_something( #params );
package A;
sub do_neat_thing {
my ( $class_or_instance, #args ) = #_;
my $class = ref( $class_or_instance );
if ( $class ) {
say "Instance of '$class' does a neat thing.";
}
else {
say "$class_or_instance does a neat thing.";
}
}
...
package main;
A->do_neat_thing(); # A does a neat thing.
my $a_obj = A->new();
$a_obj->do_neat_thing(); # Instance of 'A' does a neat thing.