I have two classes, one is the base class(Employee) and the other its subclass which inherits it (Extend) the codes of which are shown below :
package Employee;
require Exporter;
our #EXPORT = ("getattr");
our $private = "This is a class level variable";
sub getattr {
print "Inside the getattr function of Employee.pm module \n";
$self = shift;
$attr = shift;
return ($self->{$attr});
}
1;
================
package Extend;
use base qw(Employee);
sub new {
print "Inside new method of Employee.pm \n";
my $class = shift;
my %data = (
name => shift,
age => shift,
);
bless \%data , $class;
}
sub test {
print "Inside test method of Extend class \n";
}
1;
==================
Now I have another piece of code which is using the Extend class :
use Extend;
my $obj = Extend->new("Subhayan",30);
my $value = $obj->getattr("age");
print ("The value of variable age is : $value \n");
$obj->test();
print "Do i get this : $obj.$private \n";
My question is regarding the variable $private defined in the parent class. As per my concept of inheritance attributes and methods of the parent class should be available through the subclass object . For example the function getattr runs fine . But why am I not being able to access $private variable using the base class Extend object .
What am I missing here ? Can someone please help ?
Variables don't get inherited the same way subs do. To access it, you need to specify the entire package name (and yes, when you declare $private, you need our, not my):
print "$Employee::private\n";
It's much more robust to define accessor methods:
# Employee package
sub private {
return $private;
}
...then in your script:
my $var = private();
To inherit object attributes from Employee, you can do:
# Employee
sub new {
my $self = bless {
dept => 'HR',
hours => '9-5',
}, shift;
return $self;
}
# Extend
sub new {
my $class = shift;
my $self = $class->SUPER::new; # attrs inherited from Employee
$self->{extended} = 1;
return $self;
}
# script
my $extend = Extend->new;
Now $extend looks like:
{
dept => 'HR',
hours => '9-5',
extended => 1,
}
You most likely wouldn't set dept or hours in the base class as it will apply to all employees, but I digress.
Related
In Python you can do:
class Binance(Exchange):
name = "Binance"
code = "binance"
and in the parent class have
class Exchange:
#classmethod
def get_name(cls):
return cls.name
Now Perl!
This is lovely. I want the same for my Perl objects.
package DWDESReader;
use base qw(DWConfigFileReader);
our $type = "DES";
and in the base class:
package DWConfigFileReader;
our $type = "";
sub new {
my ($class, %args) = #_;
$args{type} = $type;
return bless {%args}, $class;
}
sub getType {
my ($self) = #_;
return $self->{type};
}
But this doesn't work, i.e. only returns the empty string assigned in the base class. I didn't expect it to work but am unsure how it should be done.
I don't see why one should need it, but it's possible, if you turn off strict refs:
#!/usr/bin/perl
use warnings;
use strict;
{ package My::Base;
sub new { bless {}, shift }
our $name = 'Base';
sub get_name {
my ($self) = #_;
my $class = ref $self || $self;
do { no strict 'refs';
${ $class . '::name' }
}
}
}
{ package My::Child;
use parent -norequire => 'My::Base';
our $name = 'Child';
}
my $ch = 'My::Child'->new;
print $ch->get_name, ' ', 'My::Child'->get_name;
But usually, you would just define a class method holding the name:
{ package My::Base;
sub new { bless {}, shift }
sub name { 'Base' }
sub get_name { shift->name }
}
{ package My::Child;
use parent -norequire => 'My::Base';
sub name { 'Child' }
}
Classes don't have attributes (variables) in Perl, only methods (subs).
I recommend creating an abstract virtual class method.
package DWConfigFileReader;
use Carp qw( croak );
sub new {
my ($class, %args) = #_;
my $self = bless(\%args, $class);
return $self;
}
sub type { croak("Subclass must override \"type\"."); }
1;
package DWDESReader;
use parent 'DWConfigFileReader';
sub type { "DES" }
1;
You don't even need $self->{type} = $class->type;; just use $self->type instead of $self->{type}.
As has been suggested, Perl inherits methods (subs), not variables, but constants are actually subs, so you can do something similar like this.
package DWDESReader;
use base qw(DWConfigFileReader);
use constant TYPE => "DES";
Then, if you call $self->TYPE somewhere in the base class, you'll get "DES" if the object is actually a DWDESReader object.
Is there a way to fetch the objects of a particular class in perl ?
Example :
use <class1>;
use <class2>
sub Main {
my $call1 = <class1>->new(<ARGS>)->(<Routine call>);
my $call2 = <class1>->new(<ARGS>)->(<Routine call>);
my $call3 = <class1>->new(<ARGS>)->(<Routine call>);
.
.
.
my $call4 = <class2>->new(<ARGS>)->(<Routine call>);
}
Would one be able to fetch the objects of <class1> ?
$call1
$call2
and
$call3
There are a few pointers here:
How can I list all variables that are in a given scope?
With this tool: http://search.cpan.org/dist/PadWalker/PadWalker.pm you can access all of the package and lexcial variables in a given scope.
Or you can access the symbol table also directly for a given scope: keys %{'main::'}
And you can get the type/class of a variable with ref(). http://perldoc.perl.org/functions/ref.html
I don't think there are direct solutions for your problem.
Perhaps you could extend the class and collect the instances to a hash table in an overridden constructor.
The normal technique would be to write Class1 in such a way that its constructor keeps a (presumably weak) reference to each object that is constructed in an array or hash somewhere. If you're using Moose, there's an extension called MooseX::InstanceTracking that makes that very easy to do:
package Class1 {
use Moose;
use MooseX::InstanceTracking;
# ... methods, etc here.
}
package Class2 {
use Moose;
extends 'Class1';
}
my $foo = Class1->new;
my $bar = Class1->new;
my $baz = Class2->new;
my #all = Class1->meta->get_all_instances;
If you're not using Moose; then it's still pretty easy:
package Class1 {
use Scalar::Util qw( weaken refaddr );
my %all;
sub new {
my $class = shift;
my $self = bless {}, $class;
# ... initialization stuff here
weaken( $all{refaddr $self} = $self );
return $self;
}
sub get_all_instances {
values %all;
}
sub DESTROY {
my $self = shift;
delete( $all{refaddr $self} );
}
# ... methods, etc here.
}
package Class2 {
our #ISA = 'Class1';
}
my $foo = Class1->new;
my $bar = Class1->new;
my $baz = Class2->new;
my #all = Class1->get_all_instances;
I have a legacy project and I would like to extend a couple of classes in it with a few attributes and methods. I have access to the source code and know that the class uses a blessed hashref. I can of course go ahead and extend that hashref adding the keys that I want and re-bless into my class. But obviously this breaks encapsulation and I would like to avoid it as much as I can.
Is there a way to extend a (non-Moose) Perl class with attributes, not just methods, in a way that does not break encapsulation of the orginal class? The option to use Moose to do this is not available. Thank you.
First, one best practice for writing objects based on hashrefs is to prefix all fields with the package name, e.g.
package Parent;
sub new {
my ($class, $x, $y) = #_;
bless { "Parent::x" => $x, "Parent::y" => $y } => $class;
}
sub x { shift()->{"Parent::x"} }
sub y { shift()->{"Parent::y"} }
In that case, the issue doesn't arise, as every class has its own attribute namespace. But who writes his classes that way?
There are two ways I can think of to circumvent any problems: Proxying the original object via Autoload, or using inside-out object patterns. The third solution is to use prefixed attributes in your class, and hope that the parent never ever uses these names.
Inside-Out Objects
An inside-out object uses the blessed reference as an ID, and stores the attributes in lexical variables inside your class:
package Child;
use Scalar::Util qw/refaddr/;
use parent 'Parent';
my %foo;
sub new {
my ($class, $foo, #args) = #_;
my $self = $class->SUPER::new(#args);
$foo{refaddr $self} = $foo;
return $self;
}
sub foo {
my ($self) = #_;
$foo{refaddr $self};
}
sub set_foo {
my ($self, $val) = #_;
$foo{refaddr $self} = $val;
}
sub DESTROY {
my ($self) = #_;
# remove entries for this object
delete $foo{refaddr $self};
$self->SUPER::DESTROY if $self->SUPER::can('DESTROY');
}
This is a slightly dated pattern, but it works extremely well for your use case.
Proxy objects
We can contain a parent instance in a field of our class (i.e. both has-a and is-a relationship). Whenever we encounter unknown methods, we delegate to that object:
package Child;
use Parent ();
our $SUPER = 'Parent';
use Carp;
sub new {
my ($class, $foo, #args) = #_;
bless {
parent => $SUPER->new(#args),
foo => $foo,
} => $class;
}
sub foo {
my ($self) = #_;
$self->{foo};
}
sub set_foo {
my ($self, $val) = #_;
$self->{foo} = $val;
}
# manually establish pseudo-inheritance
# return true if our class inherits a given package
sub isa {
my ($self, $class) = #_;
return !!1 if $class eq __PACKAGE__;
return +(ref $self ? $self->{parent} : $SUPER)->isa($class);
}
# return a coderef to that method, or false
sub can {
my ($self, $meth) = #_;
my %methods = (new => \&new, foo => \&foo, set_foo => \&set_foo, DESTROY => \&DESTROY);
if (my $code = $methods{$meth}) {
return $code;
}
# check parent
my $code = ( ref $self ? $self->{parent} : $SUPER)->can($meth);
return undef unless $code;
return sub {
my $self = shift;
unshift #_, ref $self ? $self->{parent} : $self;
goto &$code;
};
}
# write explicit destroy to satisfy autoload
sub DESTROY {
my ($self) = #_;
$self->{parent}->DESTROY if ref $self and $SUPER->can('DESTROY');
}
sub AUTOLOAD {
# fetch appropriate method coderef
my $meth = our $AUTOLOAD;
$meth =~ s/.*:://; # clean package name from name
my $code = $_[0]->can($meth);
$code or croak qq(Can't locate object method "$meth" via package "#{[__PACKAGE__]}");
goto &$code;
}
The ugly part is to fake methods defined in superclasses in the can code: We have to wrap the actual method inside a anonymous sub that unpacks our object to call the method on the proxied object. The gotos make our extra levels invisible to the called code, which is neccessary when somebody uses caller.
Most of this boilerplate proxying code can be abstracted into another module (and probably is, somewhere on CPAN).
How would I create my class such that some methods will exist in the instance only if certain values were passed to the constructor?
Perhaps a more generic way of asking is: How can I add a method to an existing class instance?
You can attach an anonymous sub to an object based on flags:
use strict;
use warnings;
package Object;
sub new {
my $class = shift;
my $self = bless {}, $class;
my %args = #_;
if ($args{method}) {
$self->{method} = sub { print "hello\n" }
}
return $self;
}
sub method {
my $self = shift;
if (not defined $self->{method}) {
warn "Not bound\n";
return;
}
$self->{method}->();
}
1;
to use:
use Object;
my $obj1 = Object->new(method=>1);
$obj1->method();
my $obj2 = Object->new();
$obj2->method();
You can extend this to a number of methods through the same interface.
You can use Moose to apply a role at runtime.
package My::Class;
use Moose;
has foo => ( isa => 'Str', is => 'ro', required => 1 );
sub BUILD {
my $self = shift;
if ($self->foo eq 'bar') {
My::Class::Role->meta->apply($self);
}
}
no Moose;
package My::Class::Role;
use Moose::Role;
sub frobnicate {
my $self = shift;
print "Frobnicated!\n";
}
no Moose;
my $something = My::Class->new( foo => 'bar' );
print $something, "\n";
$something->frobnicate;
my $something_else = My::Class->new( foo => 'baz' );
print $something_else, "\n";
$something_else->frobnicate;
Gives:
Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x2fd5a10)
Frobnicated!
My::Class=HASH(0x2fd2c08)
Can't locate object method "frobnicate" via package "My::Class" at testmoose.pl line 32.
use AUTOLOAD to define the function. As a example method foo is called if $self->{foo} exists
sub AUTOLOAD {
my $methodname = $AUTOLOAD;
if ($methodname eq "foo" && exists($_[0]->{foo})){
goto &fooimplementationsub;
}
return;
}
An alternative technique is to use globs to define a new method at runtime
*PACKAGE::method = sub {
#code here
};
This has the disadvantage that the method is now visible to all instances of the class so is not quite what you want.
A third and possibly more risky/inefficient method is to use string eval
eval <<EOF
sub foo {
#code here
};
EOF
Again this has the disadvantage that the method is now visible to all instances of the class so is not quite what you want.
Methods are just subroutines in a package, and a package is just a hash holding typeglobs. And hashes can be modified at runtime.
So you could, in theory, add or remove methods given values in a constructor.
package WeirdClass;
sub new {
my ($class, $name, $code) = #_;
if ($name) {
no strict;
*{__PACKAGE__ . "::$name"} = $code;
}
bless {} => $class;
}
And then use it like:
my $object = WeirdClass->new(foo => sub {say "foo"});
$object->foo(); # prints "foo\n";
However, this method is available for all objects of that class:
my $another_object = WeirdClass->new();
$another_object->foo; # works too.
Using autoload, one can mock arbitrary methods:
package BetterClass;
sub new {
my ($class, %args) = #_;
bless \%args => $class;
}
# destructor will be called at cleanup, catch with empty implementation
sub DESTROY {};
sub AUTOLOAD {
my $self = shift;
(my $method = our $AUTOLOAD) =~ s/.*://; # $AUTOLOAD is like "BetterClass::foo"
# check if method is allowed
die "forbidden method $method" unless $self->{can}{$method};
# mock implementations
given ($method) {
say "foo" when "foo";
say "bar" when "bar";
when ("add") {
my ($x, $y) = #_;
return $x + $y;
}
default { die "unknown method $method" }
}
}
Then:
my $o = BetterClass->new(can => { foo => 1, bar => 0});
$o->foo;
my $p = BetterClass->new(can => {bar => 1, add => 1});
$p->bar;
say $p->add(5, 6);
Of course, these techniques can be combined freely.
Edit: can()
To make the AUTOLOAD work with can, the protected methods should be moved into a data structure:
my %methods;
BEGIN {
%methods = (
foo => sub {say "foo"},
bar => sub {say "bar"},
add => sub {
my ($self, $x, $y) = #_;
$x + $y;
},
);
}
Then override the can method:
# save a reference to the origional `can` before we override
my $orig_can;
BEGIN{ $orig_can = __PACKAGE__->can("can") }
sub can {
my ($self, $meth) = #_;
# check if we have a special method
my $code = $methods{$meth} if ref $self and $self->{can}{$meth};
return $code if $code;
# check if we have a normal method
return $self->$orig_can($meth);
}
And AUTOLOAD would change to
my ($self) = #_; # do not `shift`
(my $method = our $AUTOLOAD) =~ s/.*://;
my $code = $self->can($method) or die "unknown method $method";
goto &$code; # special goto. This is a AUTOLOAD idiom, and avoids extra call stack frames
Don't do too much magic. I've gotten away from AUTOLOAD because it causes maintenance issues where mysterious methods suddenly appear and disappear.
One way to handle what you want is to define all the methods you need, and if a particular object is of the wrong type, simply cause that method to croak:
sub Foo {
my $self = shift;
my $parameter = shift;
if ( $self->Class_type ne "Foo" ) {
croak qq(Invalid method 'Foo' on object #{[ref $self]});
}
print "here be dragons\";
return "Method 'Foo' successfully called";
}
The above will not allow method Foo to be called unless the class type is Foo.
If your objects won't change (or you don't want them to change) once an object is created, you can define that object as a sub-class.
Before you bless a newly created object, check that special value and decide whether or not you need to create a specific sub-class instead.
package My_class;
sub new {
my $class = shift;
my $class_type = shift;
my $self = shift;
if ( $class_type eq "Foo" ) {
bless $self, "My_class::Foo";
}
else {
bless $self, $class;
}
package My_class::Foo;
use base qw(My_class);
sub Foo {
my $self = shift;
return "Foo Method successfully called!";
}
Notice that my class My_class::Foo is a sub-class of My_class via the use base pragma. That means all methods for My_class are valid with objects of My_class::Foo. However, only objects of My_class::Foo can call the Foo method.
When I create my object (via the new subroutine), I look at the $class_type parameter. If it's a type Foo, I bless the class as My_class::Foo.
Here's an example where I use sub-classes to do what you want.
Every object is a class type of Question. You can see my constructor on line 1129. I pass in a question type as one of the parameters to my constructor.
In line 1174 to 1176, I create my object, but then append the question type to the class, and then bless the question as that sub-class type. All of my subclasses are a type Question (see my use base qw(Question); below each package declaration. However, only questions of sub-class Question::Date and Question::Regex have a method Format. And, only objects of type Question::Words have a method Force.
Hope this helps.
None of the answers so far given actually handle the question actually asked.
Adding methods to an instance in Perl is not directly supported. Object instances are always instances of some class, and that class is the thing that actually has methods. You cannot add a method to a single instance of a class, without making that method also available on every other instance of the same class.
For your problem you have two basic solutions:
Provide the methods always, but test a flag to see whether the method should apply to the given instance or not. This is by far the simplest.
Bless each object into subclasses depending on the flags. Subclass the main class to provide those methods as appropriate.
If you truely want to add methods on individual instances, then what you'll have to do is arrange that every instance is a single instance of a newly-derived class for every object. This gets harder to arrange for, doubly-so if you want to avoid leaking memory and cleaning up the classes once the objects are DESTROYed. This would however allow truely per-instance methods.
Since it is highly unlikely you'll truely need this third option it is far better to go with one of the first.
How do you make one setter method, and one getter method to manage access to fields of an object? The new subroutine looks like this:
sub new {
my $class = shift;
my $self = {#_};
bless($self,$class); # turns this into an object
}
Creation of a new object looks like this:
$foo = Package::new("Package",
"bar", $currentBar,
"baz", $currentBaz,
);
This is not a good idea.
Perl instituted the use of use strict; to take care of problems like this:
$employee_name = "Bob";
print "The name of the employee is $employeeName\n";
Mistyped variable names were a common problem. Using use strict; forces you to declare your variable, so errors like this can be caught at compile time.
However, hash keys and hash references remove this protection. Thus:
my $employee[0] = {}
$employee[0]->{NAME} = "Bob";
print "The name of the employee is " . $employee[0]->{name} . "\n";
One of the reasons to use objects when you start talking about complex data structures is to prevent these types of errors:
my $employee = Employee->new;
$employee->name("Bob");
print "The name of the employee is " . $employee->Name . "\n";
This error will get caught because the method name is name and not Name.
Allowing users to create their own methods at random removes the very protection we get by using objects:
my $employee = Employee->new;
$employee->name("Bob"); #Automatic Setter/Getter
print "The name of the employee is " . $employee->Name . "\n"; #Automatic Setter/Getter
Now, because of automatic setters and getters, we fail to catch the error because any method the user names is valid -- even if that user made a mistake.
In fact, I setup my objects so my object doesn't necessarily know how it's structured. Observe the following class with methods foo and bar:
sub new {
my $class = shift;
my $foo = shift;
my $bar = shift;
my $self = {};
bless $self, $class;
$self->foo($foo);
$self->bar($bar);
return $self;
}
sub foo {
my $self = shift;
my $foo = shift;
my $method_key = "FOO_FOO_FOO_BARRU";
if (defined $foo) {
$self->{$method_key} = $foo;
}
return $self->{$method_key};
}
sub bar {
my $self = shift;
my $bar = shift;
my $method_key = "BAR_BAR_BAR_BANNEL";
if (defined $bar) {
$self->{$method_key} = $bar;
}
return $self->{$method_key};
}
I can set the class values for foo and bar in my constructor. However, my constructor doesn't know how those values are stored. It simply creates the object and passes it along to my getter/setter methods. Nor, do my two methods know how they store each other's value. That's why I can have such crazy names for my method's hash keys because that is only available in the method and no where else.
Instead, my methods foo and bar are both setters and getters. If I give them a value for foo or bar, that value is set. Otherwise, I simply return the current value.
However, I'm sure you already know all of this and will insist this must be done. Very well...
One way of handling what you want to do is to create an AUTOLOAD subroutine. The AUTOLOAD subroutine automatically is called when there's no other method subroutine by that name. The $AUTOLOAD contains the class and method called. You can use this to setup your own values.
Here's my test program. I use two methods bar and foo, but I could use any methods I like and it would still work fine
One change, I use a parameter hash in my constructor instead of a list of values. No real difference except this is considered the modern way, and I just want to be consistent with what everyone else does.
Also notice that I normalize my method names to all lowercase. That way $object->Foo, $object->foo, and $object-FOO are all the same method. This way, I at least eliminate capitalization errors.
use strict;
use warnings;
use feature qw(say);
use Data::Dumper;
my $object = Foo->new({ -bar => "BAR_BAR",
-foo => "FOO_FOO",
}
);
say "Foo: " . $object->foo;
say "Bar: " . $object->bar;
$object->bar("barfu");
say "Bar: " . $object->bar;
say Dumper $object;
package Foo;
sub new {
my $class = shift;
my $param_ref = shift;
my $self = {};
bless $self, $class;
foreach my $key (keys %{$param_ref}) {
# May or may not be a leading dash or dashes: Remove them
(my $method = $key) =~ s/^-+//;
$self->{$method} = $param_ref->{$key};
}
return $self;
}
sub AUTOLOAD {
my $self = shift;
my $value = shift;
our $AUTOLOAD;
( my $method = lc $AUTOLOAD ) =~ s/.*:://;
if ($value) {
$self->{$method} = $value;
}
return $self->{$method};
}
Something like this...
sub get {
my $self = shift;
my $field = shift;
return $self->{$field};
}
sub set {
my $self = shift;
my $field = shift;
$self->{$field} = shift;
}
...makes it possible to write
$obj->set(foo => 'my foo value');
print $obj->get('foo');
But nowadays, it is very common to just use Moose.