develooper 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



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About