bluppfisk
bluppfisk

Reputation: 2652

Parent method using a variable defined in a child class

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.

Upvotes: 1

Views: 769

Answers (3)

ikegami
ikegami

Reputation: 385496

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}.

Upvotes: 3

TFBW
TFBW

Reputation: 1019

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.

Upvotes: 3

choroba
choroba

Reputation: 241748

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' }
}

Upvotes: 4

Related Questions