Front page | perl.perl5.porters |
Postings from November 1999
Re: assignment overload [Was: [ID 19991101.002] Data::Dumper 2.101 and
From:
Barrie Slaymaker
Date:
November 10, 1999 21:45
Subject:
Re: assignment overload [Was: [ID 19991101.002] Data::Dumper 2.101 and
Message ID:
382A593C.E7D054E0@slaysys.com
John Macdonald wrote:
>
> When you write:
>
> my $x = 1; # $x has an integer value
> $x = 'abc'; # now it has a string value
>
> you don't expect the second assignment to be affected by the
> previous contents of $x. The old contents are simply replaced
> with the new contents *and its type*.
And that's a clear statement of the problem. It all hinges on
the meaning of 'contents': are the contents of a reference the
reference or the referred-to value? Perl considers it to be
the reference itself. What I'm asking for is to have the option
to completely emulate scalars and be able to define scalar-like
objects for which the contents are the referred-to value. The
option of extending weak typing to be able to include some blessed
references.
It would allow people to make simple-as-a-scalar APIs.
Consider:
my $x = 1 ;
my $y = Math::BigInt->new( 10 ) ;
... much code passes ...
$y += 1 ;
$x = $y ;
${x}'s old contents are _not_ replaced by ${y}'s contents ('11'),
but the type has been replaced. Do a
$y->internal( 2 ) ; ## not a public API, but you get my point
some time later, in a module far, far away, and the value of $x
gets whammied at a distance. Which can be a subtle problem if
you're not expecting it.
What I'm proposing is an overloaded assignment operator
appropriate for a weakly typed language.
In my simple way, I'm thinking of something like:
---------8<------------
package MyInt ;
use overload "assign" => \&assign ;
...
sub assign {
## Call copy ctor
return shift->new() ;
}
---------8<------------
So:
my $a = MyInt->new( 6 ) ;
my $b = $a ; ## calls MyInt::assign( $a )
$a = 5 ; ## sets $a to be a scalar containing the integer 5
print "$a $b\n" ;
would yield the least surprising (IMO) output "5 6\n" and leave $a
a scalar and $b a MyInt.
That's necessarily as powerful a metaphor as you get when the type
of the target is immutable, as it is in strongly typed languages.
But it's exactly this approach that's made Perl so nice: ints,
floats, strings, and CORE::God knows only what else work that way.
It's DWIM.
If you want something more like a strongly typed language, then
this next bit could be used to implement
- weak typing,
- 'clingy' typing, which allows the target to try to
preserve it's type, but also allows it to revert
back if it can't, or
- a poor man's strong typing, only checked at run time and
with none of the nice optimizations possible under real strong
typing,
all at the author's discretion.
---------8<------------
package MyInt ;
use overload "assign" => \&assign ;
use Carp ;
use UNIVERSAL qw( isa ) ;
## Set $mode to 'weak', 'clingy', or 'strong'
my $mode = 'clingy' ;
...
sub assign {
my ( $dest, $source ) = @_ ;
if ( isa( $dest, "MyInt" ) ) {
if ( $mode ne 'weak' && $source =~ /^\d*$/ ) {
## Preserve the destination's type
return $dest->set_to( $source ) ;
}
else {
carp "Can't assign $source to a MyInt"
if $mode eq 'strong' ;
cluck "watch out: assignment throwing away MyInt status"
if $^W ;
return $source ;
}
}
else {
## We're assigning to a scalar, there is no meaningful
## thing in $dest, but I suppose you could want to know
## the value $dest for debugging purposes. Here, I don't
## care.
##
## Call copy ctor
return $source->new() ;
}
}
## Assume similar code in package MyOtherInt.
---------8<------------
Then:
my $a = MyInt->new( 6 ) ;
my $b = MyOtherInt->new( 7 ) ;
$b = $a ; ## calls MyOtherInt::assign( $b, $a )
$a = 5 ; ## calls MyInt::assign( $a, 5 )
print "$a $b\n" ;
Would output "5 6\n" and leave the types of $a and $b alone.
Overloading collisions would be resolved by calling the target's
overload, as shown by the line "$b = $a ;".
It's late. I'm probably ignoring something here. Ignorance is
bliss :-). I'm not sure whether weak, clingy or strong typing is least
surprising. I suspect that it would be application and programmer
dependant. Weak would be least surprising in most cases, probably,
and simplest to explain. The so-called "strong" typing shown here
is not a good idea given my Dog $spot ; it would lead to metaphor
confusion.
And this all may be a bit much, especially if assignment overloading's
tough or expensive to implement. But to be able to extend the range
of types that behave like scalars would be nice.
- Barrie