I wrote a subroutine to be callable either passing a floating point number or a reference to an array of such. (I specifically die if caller passes a list.) It can return a scalar if called in a scalar context, or a transform of the original array if called in a list context and passed that reference. What if I want to operate on the passed array itself? Then I call it in a void context, like the way we call chomp.

So wantarray should be undefined! But NooOOOooo! It returns a 1! This forces my code into logic for which it was not intended. So the bottom line for this post is: Why is wantarray returning a 1 when I clearly had called the function in void context? It should be undefined.

My workaround it not to be so blessed clever and always return something, even in void context but then I don't learn the correct solution to operating in place or not. (In fact, the earlier, working, version was scalar parameter with scalar context only; I was using the map {} command to operate on the whole array.)

Hi, I don't quite understand or get what you want to use your subroutine for. Though that been said, I think you are not really getting wantarray. Please do perldoc -f wantarray to see how to properly use it. Suggestions: 1. Pass an array reference to your sub, then check if is an array ref, else the sub dies. 2. then using wantarray, return a list if your subroutine is called in a list context or a 'scalar' of the list generated within your sub, if the subroutine is called in a scalar context. Like so:

## I also expect this to die print realify(qw(apple banana 1234 3.169));

## I also expect this to die print realify( 1 / 10 );

sub realify { my ($val) = @_; ## or use shift.

die "You can only pass ARRAY reference" unless ref $val eq 'ARRAY';

wantarray ? return @$val : return scalar @$val; }

Please NOTE the context in which the subroutine is called. NOTE: The script above is to illustrate the point mention, you might have to do much more to get what you wanted. Also note how, what is pass into the sub. was checked. Using '$_[0]' like you did, might not be what you are really looking for.

I want to be able to call the function in void context. That means no return value is expected. The function recognizes this call context by noting that "wantarray" is undefined. But that's what blew up in my face; I could see, via the debugger, that wantarray was not only defined but was set to 1, indicating a list context call.

Man, that has *GOT* to be just plain wrong! And it's a pretty good bet that Perl is not at fault. Hence, I'm trying to figure out where my logic has gone haywire.

As intended, once realify() realizes it was called in void context (as indicated by undefined wantarray), it would operate directly on the parameter (passed by reference), with no need to return anything. (Your suggestion always has something being returned. Not my plan.)

In this situation, I do *NOT* want to execute a return(something); I just want to fall back to the caller with no returned value. Your suggestion is concentrating on the parameter that was passed. In the context of my question, it doesn't matter; I care about what the caller expects me to return (or not).

Sorry to be so verbose - it's my affliction anyway - but I want to be perfectly clear about this. (Channeling Tricky Dicky? I need to hit the sack!) -------------------- -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)

If you are passed an array ref, then your function will probably modify the array itself, and you probably don't want to return the array but probably only a boolean return code (success or failure, modified the aray or not, something like this) or even possibly nothing.

It's time for me to put my cards on the table. (Boy is this gonna be long winded! ) The bottom line, Fishmonger, is that I have divorced the parameter context from the return context.

The module I am writing is for numerical calculations involving real and complex numbers. With the inevitable rounding errors, even in a 64-bit machine, occasionally you get a a number (or component of a complex number) so close to 0 that you just know it would have been 0 in a perfect world.

Motivation: If you feed a real number into the function Math::Complex::root($some_real,3), you would think you get back one one real root; instead your real comes back as a complex with a teeny (but non-zero) Im component. I needed to get rid of that.

The original, working just fine version of realify() accepts a scalar or a reference to a complex number.

If the absolute value is very low (based on a global variable, $margin) it returns a 0 (real). This applies to either a real or complex number

If the imaginary component is similarly very low, it returns only the real component (cplx->Re). (Hence the name: "realify".)

If the real component (->Re) is tiny, it returns a complex number with the same Im component but 0 in the Re component.

All without messing with the original parameter. In usage:

Code

$smoother = realify($calculated); # Make a corrected copy of original $calculated = realify($calculated); # Correct the original in place @corrected_list = map {realify($_)} @calculated_list; # Get corrected array without messing up the original. @calculated_list = map {realify($_)} @calculated_list; # Correct original list in place

All without messing up the original parameter, although I could have done so easily just by manipulating $_ in the function. Here's the original (worked just fine) code:

if (ref($thing) eq $class_cplx) # Here we lose components that are so { # tiny that we assume them to be errors # If imaginary component is really tiny, remove it from the number, # producing a real. # $thing = $thing->Re if (abs($thing->Im) < $margin);

# Hey, the real component might also be tiny but have a disruptive presence. # if (ref($thing) eq $class_cplx) # If I have not realified it above then { # I am permitted to check its components $thing = cplx(0.0, $thing->Im) if (abs($thing->Re) < $margin); # Need to keep real part, even if tiny } } # If it was real but tiny, we already took care of that. Nothing left to # do but return the transformed parameter # return $thing; }

By the way, I just noticed a logic bug that I have not encountered in testing. But that is separate from my question.

Now I wanted to get clever about this, mainly as an exercise in get-your-hands-dirty Perl and decided to make all sorts of options, as I've described in my opening post to this thread. The above code - scalar or complex -> same - is still at the heart of the logic. But anything other scheme - scalar/list/void context or scalar/list-reference parameter, makes recursive calls to itself to reduce the problem to the original scheme. The code is not a role model of efficiency but does (I think) cover all possibilities. Here's that code:

# If either component of a complex number is really tiny, set it to 0. # And if it's the imaginary component, lose it altogether # if (ref($thing) eq $class_cplx) # If I have not zeroed it above then { # I am permitted to check its components $rval = $thing; # Preserve original complex number if (abs($thing->Re) < $margin) # Need to keep real part, even if tiny { $rval = cplx(0.0, $thing->Im) # So just zero it out } if (abs($thing->Im) < $margin) # If imaginary component is tiny { $rval = $thing->Re; # lose it completely and return a real } } return $rval; } else # Void context: Operate on the passed object. { if (ref($thing) eq "ARRAY") # Realifying every element in an array? { @{$thing} = realify($thing); # Tickle the wantarray code above } else # Realify only one object { # Just work on that one $_[0] = realify($_[0]); # Tickle the defined(wantarray) code above } } }

So now, if I want to operate in place, I would use:

Code

realify($calculated); # Correct the original in place @corrected_list = realify(\@calculated_list); # Get corrected array without messing up the original. realify(\@calculated_list); # Correct original list in place

The problem: This was called to realify an array (passed as a reference) in place. When I make the second recursive call, which is scalar to scalar (happens to be the number 1), it should, I think, tickle the defined(wantarray) code, as in the comment. Instead it tickles the "if (wantarray)" code and sties to treat the scalar '1' as an array reference. It barfs, of course:

Quote

Can't use string ("1") as an ARRAY ref while "strict refs" in use at ... line 602 ::realify(1) called at ... line 602 ::realify('ARRAY(0x80a1ad60)') called at ... line 630 ::realify('ARRAY(0x80a1ad60)') called at ... line 419

Now, I could go back to the original scheme; I still have the previous code and calling sequences saved. And if I were writing this on a paid project that's exactly what I would do - get it working, don't look for perfection. But I have that luxury right now and I'd really like to mold this to my will, not the other way around.

So if you have the patience to eyeball all that, please let me know what logic error I have incurred to provoke that mistaken wantarray.

The bottom line, Fishmonger, is that I have divorced the parameter context from the return context.

You don't need to divorce them, they are two completely different things.

You can call a function and pass one or several parameters to it. This can easily be verified within the called subroutine by checking the value of @_ in scalar context, which will give you the number of arguments. If 0, void, if 1, scalar, if more than 1, list (even if you pass just one array to the function, the function will see a list or parameters. If the argument is an array ref or a hash ref (or code ref or any other reference), you can check with the ref function.

The wantarray function has absolutely nothing to do with that and does not care at all about the number of arguments passed to the function in which it is called.

Used in a subroutine, the wantarray function tells you what the line of code that called that subroutine is expecting as return value(s): it could be void, a single scalar (that includes possibly a reference to something) or a list.

Maybe you know very well all this, but I had the feeling that there might some confusion in your mind on these two completely different things.

Maybe you know very well all this, but I had the feeling that there might some confusion in your mind on these two completely different things.

That's funny. Laurent. I went through all that because I perceived there was some confusion on the part of my replyers on that same point. I indeed know this quite well.

To reiterate the problem: When the function is called in a void context, in which case wantarray should not even be defined, wantarray was 1.

I will take a break from this thread for a day while I trace carefully through every blessed step of the logic in progress. -------------------- -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)

Well, look again at the test I made on post 005 of this thread. With a void context, wantarray does return an undef value. This is, I think, the standard expected behavior.

Having said that, I am not at all claiming that you should consult a psychiatrist and ask an admission ticket to the loony bin , I remember having seen in the past cases where I was also somewhat puzzled by the unexpected results of the wantarray function, although this is too long ago for me to remember the details.

Bill, are you reading my mind? The fact that the list includes complex numbers is totally incidental to this whole business but I will be postng another thread about Math::Complex and its documented refusal work with Math::BigFloat. But that's another story altogether.

Laurent, Thanks for the sympathy. How are you so sure I'm not already in an asylum? But like so many inmates in such, I have merely been misunderstood. But I got my answer and MAN is it subtle:

In the above whole function, at some point I use the map {} operator to realify the whole array, internally looping for one scalar context call for each element of the array. To probe this, I wrote the following short program, included here with line numbers:

Calling realify with void context Use of uninitialized value in printf at ./realify.pl line 25. at ./realify.pl line 25 main::realify(37) called at ./realify.pl line 8 Entered realify(37) with wantarray == <> wantrarray not defined; I was called with void context

Calling realify with scalar context Entered realify(37) with wantarray == <> Wantarray null but defined; I was called with scalar context

Calling realify with list context Entered realify(37) with wantarray == <1> Wantarray is <1>; I was called with list context

Calling in scalar context via map{} command Entered realify(31) with wantarray == <1> Wantarray is <1>; I was called with list context Entered realify(42) with wantarray == <1> Wantarray is <1>; I was called with list context Entered realify(53) with wantarray == <1> Wantarray is <1>; I was called with list context

Notice the last set of output lines? Although the map{} operator is surely calling realify() in scalar context for each element of @nums, the called function believes it was called in list context, possibly due to the @array in the LHS of the map{} operator. Oh, come on, Larry! That kind of subtlety is just not fair!

Back in my code, I converted the map{} usage to a brute force loop and, Jubilation! It loves me again! (I pound on my desk and I howling!)

Oh, by the way, when I am called in void context, the debugger does indeed report that wantarray has a value of 1. In fact, caller(0)[5] reports that the $wantarray entry is 1. But when I step down the logic, it indeed goes to all the right places. And if I try to print the value of wantarray, I get an "uninitialized value" error. (See the error message from line 25.) So that whole business about wantarray returning a 1 is a nagy piros hering (big red herring, in Hungarian), sold to me by the debugger. (Not by fishmonger? )

Problem solved, program working again, more learned than I expected. And it really is more elegant now. Though it's still a mystery to me that the debugger reports the 1 instead of undef. Can't win 'em all.

Thanks for all the efforts, Fishmonger, Laurent, 2teez (Related to fruteez?). As a reward, you have all been warned about this subtlety. -------------------- -- Rasputin Paskudniak (In perpetual pursuit of undomesticated, semi-aquatic avians)

Although the map{} operator is surely calling realify() in scalar context for each element of @nums, the called function believes it was called in list context, possibly due to the @array in the LHS of the map{} operator.

That is most probably wrong. Surely the map{} operator is working on one element of the array at a time, but the map block can return two or several values for each input element, so that map is quite obviously imposing a list context.

As an example; map receives and returns 3 values for each value of the array on the right-hand side in the following Perl one-liner:

So it is quite logical to have map giving a list context to whatever is in the map block.

In Reply To

Oh, by the way, when I am called in void context, the debugger does indeed report that wantarray has a value of 1. [..] Though it's still a mystery to me that the debugger reports the 1 instead of undef.

That's exactly it, now I remember clearly.

When I said earlier that I remembered having seen in the past cases where I was also somewhat puzzled by the unexpected results of the wantarray function, that was when trying it under the debugger.