Can overloaded '+' return an array? If so, how?

P

PeterSShenkin

The following sample code prints:

combine: result= [1 2 3 4]
main: ar = [4]

I expect it to print:

combine: result= [1 2 3 4]
main: ar = [1 2 3 4]

The issue is that "combine", which is the function that '+' maps to,
returns an array. When, in the main program, I say:

my @ar = $ca1 + ca2

I expect the "combine" function to be called in list context. But
evidently it is called in scalar context, because my @ar variable
receives the cardinality of the "result" array, rather than a copy of
the array.

Looking at Ch 13 of the Camel book, I don't see any restriction on
return values of overloaded operators; but maybe I'm just missing it.
If there's a way to do it, but I'm doing it wrong, I'd like to know
that. Either way, please advise.

(If, instead of what I do in the example, I return a reference to the
array, and alter my main routine correspondingly, then, of course,
everything works.)

Thanks,
-P.

Example:

====================
use strict;

my $ca1 = ClassAct->new( 1, 3 );
my $ca2 = ClassAct->new( 2, 4 );

my @ar = $ca1 + $ca2;
print "main: ar = [@ar]\n";

{
package ClassAct;

use overload (
'+' => "combine",
fallback => 1,
);

sub combine {
my $obj1 = shift;
my $obj2 = shift;
my @result = sort ( @{$obj1}, @{$obj2} );
print "combine: result= [@result]\n";
return @result;
};

sub new {
my $class = shift;
my $self = [
];
while( my $value = shift ) {
push @{$self}, $value;
}
bless $self, $class;
return $self;
}
}
====================
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
PeterSShenkin
The issue is that "combine", which is the function that '+' maps to,
returns an array. When, in the main program, I say:

my @ar = $ca1 + ca2

I expect the "combine" function to be called in list context.

Some hints: you forgot about cryptocontext. What would you think

myMultiplyArgs($ca1 + $ca2, $ca3 + $ca4, $ca5 + $ca6)

would return if your semantic would hold?

Overloading changes IMPLEMENTATION of operations; the SEMANTIC returns
the same.
(If, instead of what I do in the example, I return a reference to the
array, and alter my main routine correspondingly, then, of course,
everything works.)

Enjoy it. ;-)

Hope this helps,
Ilya
 
X

xhoster

PeterSShenkin said:
The following sample code prints:

combine: result= [1 2 3 4]
main: ar = [4]

I expect it to print:

combine: result= [1 2 3 4]
main: ar = [1 2 3 4]

The issue is that "combine", which is the function that '+' maps to,
returns an array. When, in the main program, I say:

my @ar = $ca1 + ca2

I expect the "combine" function to be called in list context. But
evidently it is called in scalar context, because my @ar variable
receives the cardinality of the "result" array, rather than a copy of
the array.

Looking at Ch 13 of the Camel book, I don't see any restriction on
return values of overloaded operators; but maybe I'm just missing it.

If there's a way to do it, but I'm doing it wrong, I'd like to know
that. Either way, please advise.


Your understanding seems to be correct (all overloaded operators are
called in scalar context), and you seem to be correct that this is not
well documented. The closest thing to it seems to be, under overload's
section on <> operator:

BUGS Even in list context, the iterator is currently called
only once and with scalar context.

(This fact seems to be true for all operators, but apparently is only
considered to be a bug for the said:
(If, instead of what I do in the example, I return a reference to the
array, and alter my main routine correspondingly, then, of course,
everything works.)

Yep. And, in fact, I would usually expect an overloaded addition
operator to turn something of the same class as (at least one of) it's
operands, so I suggest that not only should it return a ref, but a ref
that is blessed into ClassAct.

Xho
 
P

PeterSShenkin

Yep. And, in fact, I would usually expect an overloaded addition
operator to turn something of the same class as (at least one of) it's
operands, so I suggest that not only should it return a ref, but a ref
that is blessed into ClassAct.

That expectation is not fulfilled either in mathematics or in Perl
native types.

In Perl, an int divided by an int is not necessarily an int.

In mathematics, the dot product of two vectors is a scalar. The outer
product is a matrix.

Thus, if the inability of an overloaded '+' to always return a scalar
was a conscious decision, I believe it was the wrong one. What if you
want to add two arrays?

Be all this as it may, my thanks to those who responded. I guessed
this is the way it would turn out, because I couldn't see anything I
was doing wrong. I'll have to add it to my list of Perl sins (along
with the inability to handle IEEE exceptional values in a standard
way).

Cheers,
-P.
 
P

PeterSShenkin

PeterSShenkin said:
Thus, if the inability of an overloaded '+' to always return a scalar
was a conscious decision, I believe it was the wrong one. What if you
want to add two arrays?

Whoops.... of course I meant "to only return a scalar...."

-P.
 
P

PeterSShenkin

PeterSShenkin said:
Whoops.... of course I meant "to only return a scalar...."


Whoops.. sigh. "if the inability of an overloaded '+' to return
anything but
a scalar was a conscious decision, I believe it was the wrong one."

I'll shut up now. :)

-P.
 
J

jl_post

PeterSShenkin said:
The issue is that "combine", which is the function that '+' maps to,
returns an array. When, in the main program, I say:

my @ar = $ca1 + ca2

I expect the "combine" function to be called in list context. But
evidently it is called in scalar context, because my @ar variable
receives the cardinality of the "result" array, rather than a copy of
the array.

...

(If, instead of what I do in the example, I return a reference to the
array, and alter my main routine correspondingly, then, of course,
everything works.)


I fiddled around with your test code, and I found that, while the
code:

my @ar = $ca1 + ca2;

is not called in list context, the following three functionally
equivalent lines:

my @ar = $ca1->combine($ca2);
my @ar = combine $ca1 $ca2;
my @ar = ClassAct::combine($ca1, $ca2);

do return an array as you want -- without the need to change the
combine() method.

(I don't know if this information is useful to you or not, but I
thought I'd share it anyway).

-- Jean-Luc
 
P

PeterSShenkin

I fiddled around with your test code, and I found that, while the
code:

my @ar = $ca1 + ca2;

is not called in list context, the following three functionally
equivalent lines:

my @ar = $ca1->combine($ca2);
my @ar = combine $ca1 $ca2;
my @ar = ClassAct::combine($ca1, $ca2);

do return an array as you want -- without the need to change the
combine() method.

I do find that both interesting and useful.

Thanks,
-P.
 
X

xhoster

PeterSShenkin said:
That expectation is not fulfilled either in mathematics or in Perl
native types.

In Perl, an int divided by an int is not necessarily an int.

division is not addition.
In mathematics, the dot product of two vectors is a scalar. The outer
product is a matrix.

multiplication is not addition.
Thus, if the inability of an overloaded '+' to always return a scalar
was a conscious decision, I believe it was the wrong one. What if you
want to add two arrays?

Then you take two arrayrefs (or object) and return an arrayref (or object).
Or are you going to say it is also a mistake that overloaded + always takes
its *arguments* in a scalar context, too?

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top