Josh Cherry | 2 Apr 2008 23:31
Picon
Favicon

Re: Perl operator overloading

Hi Jason.  Thanks for responding.

On Tue, 1 Apr 2008, Jason Stewart wrote:

> OK, it seems that version skew has set in. I'm looking at perl5.cxx
> and it seems that the assignment operator has been defined - which I
> believe I avoided because it was handled properly by perl without
> using the overload. So maybe someone else has added more, and not
> updated the tests and perlopers.swg?

Yes, that's one thing that's going on.

> I could be mistaken - but I thought I left out the assigment operator
> because it is special in perl - I thought I had both post- and pre-
> decrement/increment working... but looking through the test suite I
> only see that the post- versions are actually checked - so this is a
> bug in itself...

Assigning the result to a variable leads to trouble, apparently because 
that invokes the copy and something bad happens silently.

>>  Simple solution: make the call with reversed arguments an error, always.
>>  Reversal is indicated by the value of the third argument passed to (in
>>  this case) __sub__, which is currently ignored.
>>
>>  Fancier solution: allow the SWIG user the option of providing __rsub__, as
>>  in Python, to handle this case.  I don't know how to determine whether a
>>  method exists in Perl, but it may be fine to call it and have it be an
>>  error if it's not there.
>
> UNIVERSAL::can() test for the existence of a method:
>   my $obj = Foo->new();
>   if ($obj->can('__rsub__') { return $obj->__rsub__() ; } else { die(...) ; }
>
> something like that...

Thanks.

> Right now SWIG generates the following code:
>
> use overload
>    "-" => sub { $_[0]->__sub__($_[1])},
>    "fallback" => 1;
>
> I'm not sure that we want a true value for 'fallback'... It silently
> attempts to handle a missing subroutine. I think what you have
> suggested would be better supported by setting fallback to a false
> value - that way no MAGIC AUTOGENERATION is attempted and it raises an
> exception if the method isn't defined. Or maybe we want it to be
> 'undef' so that it attempts MAGIC AUTOGENERATION first, and then
> raises an exception otherwise.

I'm not sure how it's related to that proposal.  "fallback" of 1 may be 
undesired for other reasons though.  Especially, autogeneration of things 
that change the object, such as += and ++, makes me very nervous in light 
of this copy business that I'm not sure I understand.  It may be 
especially inappropriate for wrapped objects.  Furthermore, if these are 
very useful operators, they are likely to exist in C++ and not need 
autogeneration.  Perhaps the values of "fallback" could be settable by the 
SWIG user.

> To use can() it would look like this:
>
> use overload
>    "-" => sub { if( not $_[2] ) { $_[0]->__sub__($_[1]) }  # not reversed
>                 elsif( $_[0]->can('__rsub__) ) {
> $_[0]->__rsub__($_[1]) } # reversed
>                 else { die("reverse subtraction not supported") }
> # no __rsub__()
>               },
>    "fallback" => undef;
>
>>  3. Mutators such as operator++ are badly broken:
>
> [snip]
>
>>  This apparently has to do with the lack of an overloaded "=" to support
>>  copying.  Despite appearances, this doesn't change the meaning of "=" in
>>  Perl.  perl5.cxx supports overloading "=" with an __assign__ method, but
>>  there's no rename in perlopers.swg.  That's fine: there shouldn't be a
>>  rename of "=" from C++.  But the overload doesn't call __assign__
>>  correctly or return the right thing.  It shouldn't, in fact, do
>>  assignment, but should clone the object.  And it should be automatic, not
>>  something that the unwary user has to provide.
>>
>>  Suggested solution: Whenever a class has overloaded operators, provide an
>>  overload for "=" that calls the class's copy constructor and returns the
>>  result.  It may not have a copy constructor, but that's fine because some
>>  sort of failure is appropriate.
>
> If I understand things correctly, the __copy__() would only be used
> for the mutator overloads and not the others. But otherwise your
> solution sounds super!

Yes, I think it only gets used when operators that change the object are 
applied.  I'm not sure of the scope of the term "mutator"; += and friends 
cause it to be used too.

>>  B.  How does this interact with inheritance?  Should the overload of "="
>>  call the copy ctor of the class in which it is defined, or of the class of
>>  the object (which might be a derived class)?
>
> I can't think of why we wouldn't call the copy constructor of the
> class of the object - otherwise I would think many things might break.

In many cases that's true.  If I do

$b = $a;
$a += 1;

Perl makes a copy ($b and $a are no longer the same, which is one of the 
things that makes me nervous).  Clearly we don't want $a or $b to change 
class.  But suppose that a base class CBase defines operator++ and a 
derived class CDer does not override it.  ++der returns a CBase in C++. 
OK, that's a bad C++ design, but if Perl calls CBase's Perl-defined "=" in 
the course of handling it, should it make a CBase or a CDer?

Josh

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

Gmane