Herencia

Una clase informa a Perl que desea heredar de otra clase añadiendo el nombre de esa clase a la variable @ISA de su paquete. Por ejemplo:
package A;
@ISA = ( "B" );
indica que la clase A hereda de la clase B.

Una alternativa mas breve es usar el módulo base:

use base qw(B C);

Búsqueda de un Método

La herencia en Perl determina el recorrido de búsqueda de un método. Si el objeto no se puede encontrar en la clase, recursivamente y en orden primero-profundo se busca en las clases de las cuales esta hereda, esto es en las clases especificadas en el vector @ISA. Para ser mas precisos, cuando Perl busca por una llamada a un método como $obj->method(), realiza la siguiente secuencia de búsqueda:

  1. Si la clase en la cuál el objeto fué bendecido (digamos MyClass) tiene una subrutina method se llama
  2. Si no, si existe un vector @ISA, para cada una de las clases en el vector @ISA se repiten los pasos 1 y 2
  3. Si no, si la clase UNIVERSAL (véase la sección 6.5) tiene un método con ese nombre, se le llama
  4. Si no, si la clase actual MyClass tiene un método AUTOLOAD se le llama
  5. Si no, si una de las clases antepasadas de esta (una vez mas búscadas en orden primero profundo) contiene un método AUTOLOAD, se le llama
  6. Si no, si la clase UNIVERSAL tiene un método AUTOLOAD, se le llama
  7. Si no, se abandona la búsqueda con un mensaje de error

Esta búsqueda sólo se hace una vez por método. Una vez localizado el método se utiliza una ''cache'' para acceder al método rápidamente. Si el vector @ISA o el vector @ISA de cualquiera de los antepasados de la clase es modificado, se limpia la ''cache''.

La clase UNIVERSAL

Como vemos existe una clase especial denominada clase UNIVERSAL de la cual implícitamente hereda toda clase. Esta clase provee los métodos isa, can y VERSION (véase la sección 5.6). Es posible añadir métodos o atributos a UNIVERSAL.

El método isa

El método isa nos permite saber si una clase hereda de otra:

if ($a->isa("B")) { # El objeto a es de la clase B ... }
El método isa memoriza los valores que retorna, de manera que una vez que conoce un par no necesita realizar una segunda búsqueda. Sin embargo la modificación de los arrays @ISA en la jerarquía borra las caches:
  DB<1> @A::ISA = qw{B}; @B::ISA = qw(C); @C::ISA = ()
  DB<2> $x = bless {}, 'A'
  DB<3> x $x->isa('C')
0  1
  DB<4> @B::ISA = ()
  DB<5> x $x->isa('C')
0  ''

El método can

Hay ocasiones en las que lo que nos preocupa no es tanto a que clase pertenece un objeto como saber si dispone de un cierto método. El método can devuelve verdadero si el objeto puede llamar al método solicitado:

if ($a->can("display_object")) { # el objeto dispone del método ... }

De hecho, el valor que devuelve can es una referencia al método por el que se pregunta.

Un Ejemplo: Métodos Singleton

Simon Cozens muestra en el módulo Class::SingletonMethod y en el libro [19] como diseñar métodos singleton en Perl.

Un método singleton es uno que se aplica a un objeto particular y no a toda la clase.

La Idea de los Métodos Singleton

El ejemplo que sigue ilustra la idea de usar singletons. Aunque los objetos $a y $b pertenecen a la misma clase, sólo el objeto $a dispone del método dump.

Para crear un método singleton usamos el método singleton_method. Puesto que queremos que todo objeto pueda crear sus métodos singleton debemos ubicar singleton_method en la clase UNIVERSAL.

hp@nereida:~/Lperl/src/advanced_perl_programming2$ cat -n singleton.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use Class::SingletonMethod;
 4
 5  my $a = Some::Class->new(yuyu => 4, chuf => [ 1..5]);
 6  my $b = Some::Class->new(yuyu => 8, chuf => [0..9]);
 7
 8  $a->singleton_method( dump => sub {
 9    my $self = shift;
10    require Data::Dumper;
11    no warnings;
12    $Data::Dumper::Indent = 0;
13    print STDERR Data::Dumper::Dumper($self)."\n"
14  });
15
16  $a->dump; # Prints a representation of the object.
17  $b->dump; # Can't locate method "dump"
18
19  package Some::Class;
20
21  sub new {
22    my $class = shift;
23
24    bless { @_ }, $class;
25  }

Ejecución de singleton.pl

lhp@nereida:~/Lperl/src/advanced_perl_programming2$ singleton.pl
$VAR1 = bless( {'chuf' => [1,2,3,4,5],'yuyu' => 4}, '_Singletons::135852824' );
Can't locate object method "dump" via package "Some::Class" at ./singleton.pl line 17.

La Implantación de Singletons

El método singleton_method crea una clase para el objeto que hace la invocación - si no fué creada anteriormente - y hace que esta nueva clase herede de la clase del objeto. El algoritmo garantiza que objetos distintos tendrán clases distintas.

lhp@nereida:~/Lperl/src/advanced_perl_programming2$ sed -ne '9,23p' `perldoc -l Class::SingletonMethod` | cat -n
 1  package UNIVERSAL;
 2
 3  no warnings; no strict; # no guarantee
 4
 5  sub singleton_method {
 6      my ($object, $method, $subref) = @_;
 7
 8      my $parent_class = ref $object;
 9      my $new_class = "_Singletons::".(0+$object);
10      *{$new_class."::".$method} = $subref;
11      if ($new_class ne $parent_class) {
12          @{$new_class."::ISA"} = ($parent_class);
13          bless $object, $new_class;
14      }
15  }

Evaluación de una Referencia en un Contexto Numérico

nereida:~/doc/casiano/PLBOOK/PLBOOK> perl -wde 0
main::(-e:1):   0
  DB<1> $x = {}
  DB<2> p $x
HASH(0x8150634)
  DB<3> $y =$x+0
  DB<4> p $y
135595572
  DB<5> printf "%x",$y
8150634



Subsecciones
Casiano Rodríguez León
2009-10-04