$d
y $t
son dos Math::BigFloat
. Una asignación como:
$v = $d/$t;trata a
$d
y $t
como valores en vez de como las referencias que son a los
correspondientes objetos. Consideremos una asignación como:
$v1 = $v;La asignación hace que
$v1
y $v
sean una referencia al mismo objeto. Si posteriormente incrementamos $v1
:
$v1++;tendremos un efecto lateral, ya que
$v
se ve incrementado.
Este efecto es, cuando menos, inconsistente con el uso normal de las operadores
sobrecargados, en el sentido de que estos ''trabajan'' los referentes (objetos)
y la asignación ''trabaja'' con las referencias.
Los operadores que cambian el valor de sus operandos se llaman ''mutantes''.
El módulo overload
proporciona un medio para interceptar a los mutantes
y clonar los objetos que están siendo mutados de manera que la mutación sólo
afecte a la copia del objeto. Esta intercepción se hace sobrecargando la operador
engañosamente denominado =
package Math::BigFloat; sub copy { Math::BigFloat->new(${$_[0]}) } use overload ... '++' => "incr", '=' => "copy";Esta sobrecarga no cambia la conducta del operador de asignación. La rutina
copy
es llamada antes que la subrutina asociada con cualquier mutante.
Asi pues, el código:
$v1++;
Se traduce por:
$v1 = $v1->copy(undef,""); $v1->incr(undef,"");
$ cat -n ./fractions2.pl 1 #!/usr/local/bin/perl5.8.0 -w 2 use Number::Fraction ':constants'; 3 4 my $t = '1/2'; 5 my $x = $t; 6 $t += '1/2'; 7 print "t=$t, ref(t)=",ref($t),"\n"; 8 print "x=$x, ref(x)=",ref($x),"\n";Al ejecutarlo, produce la siguiente salida:
$ ./fractions2.pl t=1/1, ref(t)=Number::Fraction x=1/2, ref(x)=Number::Fraction¿Porqué la asignación de la línea 5 (
$x = $t
) no parece comportarse como
una asignación de referencias como se señaló en la sección anterior?.
La modificación de $t
no produce un efecto lateral sobre $x
.
Nótese que el operador =
no ha sido sobrecargado en Number::Fraction
.
Puede comprobarlo en el listado de la cabecera de Number::Fraction
que aparece en la sección 6.9.3 pagina .
Para ayudar a entender lo que esta ocurriendo, aqui tiene el código del método
add
que sobrecarga el operador +
sub add { my ($l, $r, $rev) = @_; if (ref $r) { if (UNIVERSAL::isa($r, ref $l)) { # Ambos heredan de ref $l return (ref $l)->new( # Puede que 'new' hay sido sobreescrito $l->{num} * $r->{den} + $r->{num} * $l->{den}, $r->{den} * $l->{den} ); } else { croak "Can't add a ", ref $l, " to a ", ref $r; } } else { if ($r =~ /^[-+]?\d+$/) { # $r es un número entero return $l + (ref $l)->new($r, 1); } else { # r es un double: convertimos return $l->to_num + $r; } } }
Casiano Rodríguez León