[perl] Inheritance en function references

Pagina: 1
Acties:

  • Gertjan
  • Registratie: Oktober 2001
  • Laatst online: 09-09 17:11

Gertjan

mmmm, beer...

Topicstarter
Ik heb twee classes, SubClass en SuperClass, waarbij vanzelfsprekend SubClass erft van SuperClass. Ik wil in SubClass een referentie naar een functie bij houden, die ofwel in SubClass zelf geimplementeerd wordt ofwel in SuperClass.
Op de een of andere manier krijg ik het alleen niet voor elkaar dat Perl de functie in SuperClass gaat zoeken als hij niet in SubClass geimplementeerd is.
Zie onderstaande code:

SuperClass.pm:
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/perl

package SuperClass;

use strict;
use warnings;


sub new($) {
        my $proto = shift;
        my $class = ref($proto) || $proto;

        my $self = {};
        bless $self, $class;

        return $self;
}

sub check($) {
        my $self = shift;

        print "Checking SuperClass\n";

        return;
}

1;


SubClass.pm:
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/perl

package SubClass;

use strict;
use warnings;

use base qw/SuperClass/;

sub new($) {
        my $proto = shift;
        my $class = ref($proto) || $proto;

        my $self = $class->SUPER::new();
           $self->{callback} = \✓

        bless $self, $class;

        return $self;
}

sub callback($) {
        my $self = shift;

        print "checking callback: ";

        unless( $self->{callback} ) {
                print "no callback!\n";
                return;
        }

        print "executing callback\n";

        &{ $self->{callback} };

        return;
}

1;


Ik maak een instantie van de SubClass aan, die zelf de constructor van zijn SuperClass aanroept. Daarnaast maakt hij zelf een referentie naar een functie 'check' aan. Die functie is in bovenstaand voorbeeld geimplementeerd in SuperClass.

Het probleem is nu dat Perl die functie alleen in de SubClass zoekt, en niet in SuperClass:

gertjan@dev1 ~ $ perl -I. -MSubClass -e 'my $a = SubClass->new(); $a->callback();'
checking callback: executing callback
Undefined subroutine &SubClass::check called at SubClass.pm line 37.



Om te verifieren dat de inheritance goed werkte heb ik de function reference even weggehaald uit de constructor van SubClass. Als ik dan check() aanroep op de SubClass werkt alles zoals verwacht:

gertjan@dev1 ~ $ perl -I. -MSubClass -e 'my $a = SubClass->new(); $a->check();'
Checking SuperClass

Hij pakt nu dus wel de check() methode uit SuperClass.


Wat ik echter ook niet snap, is dat als ik die function reference in de constructor van SubClass wel laat staan, ik check() niet meer rechtstreeks aan kan roepen:

gertjan@dev1 ~ $ perl -I. -MSubClass -e 'my $a = SubClass->new(); $a->check();'
Undefined subroutine &SubClass::check called at -e line 1.



Mijn bedoeling is dus om in een subklasse een function reference op te nemen, die ofwel in die klasse zelf geimplementeerd is, ofwel in zijn superklasse.
Als ik eventueel rechtstreeks bij de referentie aan moet geven dat hij de functie bij zijn parent moet zoeken vind ik dat ook niet erg, maar ook dat is me met $class->SUPER::check nog niet gelukt.

Wat nu wel een beetje lijkt te werken, is de reference aanmaken als:

Perl:
1
2
        my $self = $class->SUPER::new();
           $self->{callback} = \&SuperClass::check;


Het nadeel hiervan is, is dat dit niet heel dynamisch is; ik zou dit liever met $class->SUPER oplossen.


Dus, mijn vragen: kan iemand me uitleggen waarom "$self->{callback} = \✓" niet werkt? Waarom zoekt perl die check() niet ook in SuperClass als hij niet in SubClass is? Hoe kan ik $class->SUPER gebruiken om naar de check() methode in de parent te wijzen?

  • muba
  • Registratie: April 2002
  • Laatst online: 19-10-2013

muba

Prince of Persia!

Omdat je een referentie maakt naar check() in de huidige namespace - en SubClass::check bestaat inderdaad niet.

Maar op het moment dat je subclass onderdelen in zich heeft van superclass, lijkt het er meer op dat er een subclass has-a superclass relatie bestaat dan een subclass is-a superclass relatie.

Btw, wat is er mis met gewoon $subclassobject->check() ?

Reporter: Mister Gandhi, what do you think of western civilisation?
Gandhi: I think it would be a good idea


  • Gertjan
  • Registratie: Oktober 2001
  • Laatst online: 09-09 17:11

Gertjan

mmmm, beer...

Topicstarter
MUBA schreef op dinsdag 13 februari 2007 @ 23:18:
Btw, wat is er mis met gewoon $subclassobject->check() ?
Wat bedoel je hiermee? Waar zou ik dat in welke vorm neer moeten zetten?

Bij wijze van test heb ik het volgende nog even geprobeerd, wat in elk geval het probleem van de verkeerde namespace zou moeten elimineren.

SubClass.pm
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sub new($) {
        ...
        my $self = $class->SUPER::new();
           $self->{callback} = "check";
        ...
}

sub callback($) {
        ...
        print "executing callback\n";

        {
                no strict qw/refs/;
                &{$self->{callback}};
        }
        ...
}


Maar ook dit stuit op het feit dat Perl niet verder zoekt naar check in de parent class:

gertjan@dev1 ~ $ perl -I. -MSubClass -e 'my $a = SubClass->new(); $a->callback();'
checking callback: executing callback
Undefined subroutine &SubClass::check called at SubClass.pm line 37.


Terwijl dit wel zonder inheritance werl werkt:
gertjan@dev1 ~ $ perl -e 'use strict; my $a = "name"; sub name {print "in sub\n";} no strict qw/refs/; &$a'
in sub


Iemand enig idee?

  • muba
  • Registratie: April 2002
  • Laatst online: 19-10-2013

muba

Prince of Persia!

Gertjan schreef op woensdag 14 februari 2007 @ 14:46:
[...]

Wat bedoel je hiermee? Waar zou ik dat in welke vorm neer moeten zetten?
In deze vorm:
Perl:
1
2
my $subclass = SubClass->new;
$subclass->check();
Bij wijze van test heb ik het volgende nog even geprobeerd, wat in elk geval het probleem van de verkeerde namespace zou moeten elimineren.

SubClass.pm
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sub new($) {
        ...
        my $self = $class->SUPER::new();
           $self->{callback} = "check";
        ...
}

sub callback($) {
        ...
        print "executing callback\n";

        {
                no strict qw/refs/;
                &{$self->{callback}};
        }
        ...
}
Maar hier maak je de reference nog steeds in de SubClass namsespace, en dat is ook nog steeds de plek waar je hem aanroept.


Hier een stuk code dat werkt:
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use strict;
use warnings; 
my $s = SubClass->new;
$s->callback();






package SuperClass;

sub new {
    my $class = shift;
    my $self = {};
    return bless $self, $class;
}

sub check {
    print "Check in SuperClass\n";
}

sub createcallback {
    return \✓
}



package SubClass;

use base qw(SuperClass);

sub new {
    my $class = shift;
    my $self = {};
    $self->{callback} = $class->SUPER::createcallback();
    return bless $self, $class;
}


sub callback {
    my $self = shift;
    &{$self->{callback}};
}

Reporter: Mister Gandhi, what do you think of western civilisation?
Gandhi: I think it would be a good idea


  • Grum
  • Registratie: Juni 2001
  • Niet online
(jarig!)
In perl doe je dat soort dingen zo:

(voordeel van een compleet dynamische taal :p)

Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/perl
use strict;
use warnings;

package SuperClass;
sub new { bless {}, shift }

sub check {
    print "Checking SuperClass\n";
}

1;
package SubClass;
use base qw/SuperClass/;

sub new {
    my $class = shift;
    my $self = $class->SUPER::new;

    $self->{callback} = 'check';

    bless $self, $class;
}

sub callback {
    my $self = shift;

    my $callback = $self->{callback};
    print "checking callback: ";

    print "no callback!\n" and return unless $callback;

    print "executing callback\n";

    $self->$callback;
    ### Dit is hetzelfde als:
    # __PACKAGE__->$callback( $self );

    return;
}

1;
package main;
SubClass->new->callback;


Excuzes voor de hier en daar genomen shortcuts, tikt nou eenmaal fijner :)