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:
integer
, indicando el manipulador para enteros decimales,
float
, indicando el manejador de números en punto flotante,
binary
, indicando el manipulador de constantes octales y hexadecimales,
q
, indicando el manipulador para las cadenas constantes (esto es,
las cadenas '...'
, "..."
, q{...}
, y qq{...}
,
los argumentos de tr/.../.../
, o el segundo argumento de una sustitución
s/.../.../
,
qr
, indicando el manipulador de una expresión regular (por ejemplo,
el primer argumento de m/.../
o de s/.../.../
).
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:
q
y qr
. Para esos manipuladores toma uno de los siguientes valores:
q
, indicando que la cadena viene de un contexto no interpolable como '...'
o q{...}
o qw{...}
,
qq
, indicando que la cadena aparece en un contexto interpolable como "..."
o qq{...}
o m/.../
o el primer argumento de una sustitución s/.../.../
,
tr
, indicando que la cadena aparece en tr/.../.../
o y/.../.../
,
s
, indicando que la cadena es el segundo argumento de una sustitución s/.../.../
.
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 2Esta 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.