2 Apr 2008 23:31
Re: Perl operator overloading
Josh Cherry <jcherry <at> ncbi.nlm.nih.gov>
2008-04-02 21:31:36 GMT
2008-04-02 21:31:36 GMT
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
RSS Feed