Why is constant not automatically inherited? - perl

As we know constant in Perl is just sub,
but why are they not inherited?

As the matter of fact, they are:
use strict; use warnings;
package Father;
use constant CONST => 1;
package Child;
use base 'Father';
sub new { bless {}, shift }
package main;
my $c = Child->new;
print $c->CONST; # 1
print CONST(); # undefined subroutine

Methods are inherited, functions are not. If you want to inherit the constant, you'll need to call it like a method.
$self->FOO
or
__PACAKAGE__->FOO
That said, you should be importing constants, not inheriting them.

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

Perl prototype subroutine in class

I am trying to call a prototype function from a class without instantiating an object. An example of my class MyClass :
package MyClass;
use strict;
use warnings;
sub import{
my $class = shift;
my ($caller) = caller();
eval "sub ${caller}::myprot(\&);";
eval "*${caller}::myprot = \&MyClass::myprot;";
}
sub myprot (&) {
my ($f) = #_;
$f->();
}
1;
I want to call the prototype from a script main.pl:
use strict;
use warnings;
use MyClass;
myprot {
print "myprot\n";
};
and I am getting the errors:
Use of uninitialized value in subroutine entry at MyClass.pm line 14.
Use of uninitialized value in subroutine entry at MyClass.pm line 14.
Undefined subroutine &main::myprot called at main.pm line 8.
I don't really understand the undefined subroutine error: With use, import is called which defines the prototype for main.pl. I also really don't understand the uninitialised value error.
I'd be happy for some explanation.
You're looking for Exporter.
package MyClass;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( myprot );
sub myprot(&) {
my ($f) = #_;
$f->();
}
1;
I usually use #EXPORT_OK (requiring the use of use MyClass qw( myprot );) rather than exporting by default.
There's a bunch of sketchy things going on in that code.
Unchecked use of eval means if it fails, you'll never know. eval should be used as eval "code" or die $#. You'll find it's throwing an error because strict does not like it when you mess with the symbol table (that's what *name = \&code is doing).
Using eval to export subroutines is overkill. eval STRING is a potential security hole and should be used as a last resort (eval BLOCK is fine). You can manipulate the symbol table without eval, but strict will not like the use of symbolic references.
my $caller = "foo";
*{"${caller}::myprot"} = \&MyClass::myprot;
# Can't use string ("foo::myprot") as a symbol ref while "strict refs" in use...
You have to turn off strict first. This is generally known as "aliasing".
no strict 'refs';
*{$caller.'::myprot'} = \&myprot;
Setting the prototype beforehand is unnecessary, the alias will take care of it for you.
It turns out this is all unnecessary, there's a number of modules which do this for you. The most common one is Exporter and comes with Perl. This makes your custom import unnecessary.
use Exporter 'import';
our #EXPORT = qw(myprot);
Other general tips...
Hard coding the name of a class in a class (ie. \&MyClass::myprot should just be \&myprot) should be avoided. It makes it harder to change the class or move the code around.
Hybrid modules which are both classes and export functions, are discouraged. They're harder to use, test and document and produce odd side effects. You should put myprot into its own module.
Are you sure you really want to do this?
The problem is that the double quotes will eat the backslash you have in the glob assignment.
eval "*${caller}::myprot = \&MyClass::myprot;"
should be
eval "*${caller}::myprot = \\&MyClass::myprot;"
But please don't ask me to debug your code!

How to call method in base class in Perl

#child.pm
#!/usr/bin/perl
package child1;
use strict;
use warnings;
use Exporter;
use parent;
my #ISA=qw(cal Exporter);
sub new{
my $class=shift;
my $ref=cal->new();
bless ($ref,$class);
return $ref;
}
sub add{
my $ref=shift;
print "This is from child class";
my($a,$b)=#_;
return ($a+$b);
}
##parent.pm
#!/usr/bin/perl
package cal;
use strict;
use warnings;
use Exporter;
my #EXPORT=qw(add);
my #ISA=qw(Exporter EXPORT);
sub new{
my $class=shift;
my $ref=[];
bless ($ref,$class);
return $ref;
}
sub add{
my $ref=shift;
my $a=shift;
my $b=shift;
return ($a+$b);
}
1;
#test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Exporter;
use child;
my #ISA=qw(child1 Exporter);
my $obj=new child1();
my $sum=$obj->add(1,2);
print "$sum=sum";
I am getting the error Can't locate object method "add" via package "child1" at ./test.pl line 8.
I want to access the base class add method
and I am getting this above error
please clarify..
The main culprit here is my #ISA. For inheritance to work, you have to use the package #ISA (declare it with our).
However, there are some issues in your code beyond that:
Please use parent 'cal' instead of manipulating #ISA yourself.
Object-oriented modules have little reason to use Exporter.
The child1's new can be written without reblessing, because the parent's new is inherited. The inherited new is written in a way that already supports inheritance.
Don't give your modules lower-case names, these are reserved for “pragmas”. The parent module already exists, and I used it in my 1st point.
#ISA must be a public package variable, not a private lexical (my). Same for #EXPORT. Change my to our on all those declarations.
Even better, depending on the version of perl you have, simplify you life with either the parent or base pragma to load superclasses and to set up the class relationships.
With respect to style, you will avoid considerable confusion if you make the paths to the files that contains your modules’ code match their package names. You would do well to heed a well-established convention described in the perlmod documentation.
Module names are also capitalized unless they're functioning as pragmas; pragmas are in effect compiler directives, and are sometimes called “pragmatic modules” (or even “pragmata” if you're a classicist).
The Cal module uses an internal _initialize method as described in the perlobj documentation to facilitate inheritance of the constructor.
See below for a complete working example.
Cal.pm
package Cal;
use strict;
use warnings;
sub new {
my $class=shift;
my $self=[];
bless ($self,$class);
$self->_initialize();
return $self;
}
sub _initialize {}
sub add {
my $ref=shift;
my $a=shift;
my $b=shift;
print "This is from parent class\n";
return ($a+$b);
}
1;
Child1.pm
package Child1;
use warnings;
use strict;
use v5.10.1; # when parent was added to the core
use parent "Cal";
# if you have an older perl, use base instead of parent
# use base "Cal";
sub _initialize {
my $self=shift;
push #$self, "I am a " . ref($self) . "!";
}
sub add{
my $self=shift;
my($a,$b)=#_;
print "This is from child class\n";
return ($a+$b);
}
1;
test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Child1;
my $obj=Child1->new();
my $sum1=$obj->add(1,2);
print "$sum1=sum1\n";
# call the add method in Cal
my $sum2=$obj->Cal::add(1,2);
print "$sum2=sum2\n";
# call add as a class method of Cal, which
# happens to work in this case because Cal::add
# does not use the instance passed to it
my $sum3=Cal->add(1,2);
print "$sum3=sum3\n";
Output:
This is from child class
3=sum1
This is from parent class
3=sum2
This is from parent class
3=sum3
The .pm modules do not need, and likely do not want, the #!/usr/bin/perl lines. This is only for programs intended to be executed from the command line, like your .pl module. While you may 'perl -cw' your .pm modules, or do other command line debugging with them, such is not normal "production" use.
And .pl modules should not have #ISA, or other "our" declarations found in packages nor any exporter related things.
As said before, change "my"s for package stuff to "our"s. The "my" hides things to outsiders as if the statements were never there.
In the "cal" class, do you want something like the following? I favor SUPER as it really shows what is going on and is much more generic.
package child1;
use Exporter;
our #ISA=qw(cal Exporter);
sub new{
my $class=shift;
my $ref=$class->SUPER::new();
return $ref;
}
}
One final point: you may need a "\n" on the final print statement. Without it the buffer may not flush correctly on exit in some environments so you will never see the output.

Are the two statements always the same in perl?

$obj->SUPER::promote();
$obj->SUPER->promote();
Anyone knows if they're the same?
No. The -> operator means call a reference (in this case, an object reference), and it will look for the SUPER method, not the super base class.
Here is code to show it:
#!/usr/bin/perl -w
package MyOBJ;
use strict;
use warnings;
use Data::Dumper;
sub new {
my ($class) = #_;
my $self = {};
bless $self, $class;
return $self;
}
sub promote {
my ($self) = #_;
print Dumper($self);
}
1;
package MyOBJ::Sub;
use strict;
use warnings;
use base 'MyOBJ';
1;
use strict;
use warnings;
my $obj = MyOBJ::Sub->new();
$obj->SUPER::promote();
Run it, you'll get:
$VAR1 = bless( {}, 'MyOBJ::Sub' );
When you change the last line to use -> instead of :: you get:
Can't locate object method "SUPER" via package "MyOBJ" at test.pl line 45.
From the "perldoc perlop" manual
The Arrow Operator
If the right side is either a "[...]", "{...}", or a "(...)" subscript, then the left side must be either a hard or symbolic reference to an array, a hash, or a subroutine respectively.
Otherwise, the right side is a method name or a simple scalar variable containing either the method name or a subroutine reference, and the left side must be either an object (a blessed reference) or a class name (that is, a package name)
Since the left side is neither an object ref or a class name (SUPER is a language defined bareword for polymorphism), it's treated as a method, which doesn't exist, hence the error.

How do I use constants from a Perl module?

If I define a constant in a Perl module, how do I use that constant in my main program? (Or how do I call that constant in the main program?)
Constants can be exported just like other package symbols. Using the standard Exporter module, you can export constants from a package like this:
package Foo;
use strict;
use warnings;
use base 'Exporter';
use constant CONST => 42;
our #EXPORT_OK = ('CONST');
1;
Then, in a client script (or other module)
use Foo 'CONST';
print CONST;
You can use the %EXPORT_TAGS hash (see the Exporter documentation) to define groups of constants that can be exported with a single import argument.
Update: Here's an example of how to use the %EXPORT_TAGS feature if you have multiple constants.
use constant LARRY => 42;
use constant CURLY => 43;
use constant MOE => 44;
our #EXPORT_OK = ('LARRY', 'CURLY', 'MOE');
our %EXPORT_TAGS = ( stooges => [ 'LARRY', 'CURLY', 'MOE' ] );
Then you can say
use Foo ':stooges';
print "$_\n" for LARRY, CURLY, MOE;
Constants are just subs with empty prototype, so they can be exported like any other sub.
# file Foo.pm
package Foo;
use constant BAR => 123;
use Exporter qw(import);
our #EXPORT_OK = qw(BAR);
# file main.pl:
use Foo qw(BAR);
print BAR;
To expand on the earlier answers, since constants are really just subs, you can also call them directly:
use Foo;
print Foo::BAR;
You might want to consider using Readonly instead of constant.
package Foo;
use Readonly;
Readonly my $C1 => 'const1';
Readonly our $C2 => 'const2';
sub get_c1 { return $C1 }
1;
perl -MFoo -e 'print "$_\n" for Foo->get_c1, $Foo::C2'
To add to the bag of tricks, since a constant is just a subroutine you can even call it as a class method.
package Foo;
use constant PI => 3.14;
print Foo->PI;
If you have lots of constants it's a nice way to get at the occasional one without having to export them all. However, unlike Foo::PI or exporting PI, Perl will not compile out Foo->PI so you incur the cost of a method call (which probably doesn't matter).