next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Constructor de copia Sup: Sobrecarga de Operadores Ant: Números Fraccionarios Err: Si hallas una errata ...


Constantes

El paquete desarrollado en el ejercicio anterior permite trabajar cómodamente con números fraccionarios. Sin embargo, la forma de crearlos implica el uso explícito del constructor:
my $d = fraction->new(4,5);
Mientras que para un número podemos escribir directamente $d = 4, ya que Perl es capaz de deducir el tipo. Sería bueno que Perl pudiera convertir automáticamente constantes de tipo cadena o numéricas directamente al tipo fracción.

Para cambiar el modo en que Perl interpreta las constantes entera, flotantes, cadenas y expresiones regulares podemos crear un conjunto de ``manejadores'' mediante la subrutina overload::constant.

Se espera que dicho manejador devuelve un valor escalar que es usado en lugar de la interpretación normal. Por ejemplo, para usar overload::constant en el paquete Math::BigFloat para modificar el modo en que las constantes enteras y flotantes se interpretan en Perl haríamos:

package Math::BigFloat;
use Math::BigInt;
use overload;

my %_constant_handlers = (
  integer => sub { return Math::BigInt->new($_[0]) },
  float   => sub { return Math::BigFloat->new($_[0]) }
);

sub import { overload::constant %_constant_handlers }
sub unimport { overload::remove_constant %_constant_handlers }
Obsérve el uso de import (véase sección 6.6) que hace que overload::constant %_constant_handlers sea ejecutada en tiempo de compilación cada vez que se usa el módulo.

La subrutina overload::constant toma como argumento un hash y espera que las entradas tengan una de las siguientes claves:

El correspondiente valor para cada clave debe ser una referencia a una subrutina. La subrutina es responsable de proporcionar un valor final al tipo particular de constante que esta siendo interpretado. Se le pasan tres parámetros:


Tabla 7.4: Invocación de los manejadores de constantes
Constante Manejador Argumentos  
"doble comi" q ('doble comi', 'doble comi', 'q')  
qq{qq comi} q ('qq comi', 'qq comi', 'qq')  
'comi simples' q ('comi simples', 'comi simples', 'q')  
q{q comi} q ('q comi', 'q comi', 'q')  
qw{qw comi} q ('qw comi', 'qw comi', 'q')  
<<HERE 
docu  
HERE
q ("docu \n", "docu \n", 'qq')  
<<'HERE'
com docu 
HERE
q ("com docu \n", "com docu \n", 'qq')  
tr/desde/hacia/
q ('desde', 'desde', 'tr')  
  q ('hacia', 'hacia', 'tr')  
qr{qr comi} qr ('qr comi', 'qr comi', 'qq')  
s/s_pat/s_text/
qr ('s_pat', 's_pat', 'qq')  
  q ('s_text', 's_text', 's')  
m/m patron/ qr ('m patron', 'm patron', 'qq')  
12345 integer ('12345', 12345, undef)  
12_345 integer ('12_345', 12345, undef)  
12345.0 float ('12345.0', 12345.0, undef)  
12345e1 float ('12345e1', 123450.0, undef)  
012345 binary ('012345', 5349, undef)  
0x12345 binary ('0x12345', 74565, undef)  
0xBadDeed binary ('0xBadDeed', 195941733, undef)  


La cadena fuente pasada como tercer argumento del manejador esta definida únicamente para los manejadores q y qr. Para esos manipuladores toma uno de los siguientes valores:

El módulo Number::Fraction permite la sobrecarga de constantes. Véase un ejemplo:

$ cat fractions.pl
#!/usr/local/bin/perl5.8.0
use Number::Fraction ':constants';

my $trescuartos = '1/2'+'1/4';
print "$trescuartos\n";

my $x = '1hola'+2;
print "$x\n";

no Number::Fraction;
my $trescuartos = '1/2'+'1/4';
print "$trescuartos\n";
La salida de este program es:
$ ./fractions.pl
3/4
3
2
Esta sobrecarga se consigue definiendo import en la línea 22 del listado que sigue a continuación, para que llame a overload::constant sobre el hash %_const_handlers.

En este caso el hash tiene una única clave, ya que sólo estamos interesados en tratar las constantes de tipo cadena. Recuerde que el constructor new es el especificado en la sección 7.8.5, el cuál cuando recibe la cadena produce el objeto Number::Fraction.

En el caso de que el constructor no devuelva un objeto válido, devuelve el segundo argumento, que es el valor que Perl le da por defecto a la constante. El resultado es la conversión correcta de aquellas cadenas que pueden ser interpretadas como fracciones y que otras cadenas como '1hola' sean interpretadas de acuerdo a las tradiciones de Perl.

 1 package Number::Fraction;
 2 
 3 use 5.006;
 4 use strict;
 5 use warnings;
 6 use Carp;
 7 
 8 our $VERSION = sprintf "%d.%02d", '$Revision: 1.33 $ ' =~ /(\d+)\.(\d+)/;
 9 
10 use overload
11   q("") => 'to_string',
12   '0+' => 'to_num',
13   '+' => 'add',
14   '*' => 'mult',
15   '-' => 'subtract',
16   '/' => 'div',
17   fallback => 1;
18 
19 my %_const_handlers =
20   (q => sub { return __PACKAGE__->new($_[0]) || $_[1] });
21 
22 sub import {
23   overload::constant %_const_handlers if $_[1] and $_[1] eq ':constants';
24 }
25 
26 sub unimport {
27   overload::remove_constant(q => undef);
28 }
29 
30 sub new {
31  ...
32 }

Nótese la condición para la importación en la línea 23: if $_[1] and $_[1] eq ':constants'. Esto significa que para activar el manejador de constantes de tipo cadena el programa cliente ha de declarar

use Number::Fraction ':constants';

esto es una buena idea: cambiar el modo en que funcionan las constantes es un cambio lo suficientemente trascendental como para sólo hacerlo bajo petición explícita del usuario.

Recuerde que la función unimport se ejecutará cuando el usuario haga una llamada en su programa a no Number::Fraction. En este caso la negación produce el abandono del manejo de las constantes.


next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Constructor de copia Sup: Sobrecarga de Operadores Ant: Números Fraccionarios Err: Si hallas una errata ...
Casiano Rodríguez León
2006-02-21