Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

sub returning undef

by Scarborough (Hermit)
on May 24, 2004 at 14:32 UTC ( [id://355922]=perlquestion: print w/replies, xml ) Need Help??

Scarborough has asked for the wisdom of the Perl Monks concerning the following question:

I have a sub which if all goes well returns an array but if a error is encounted returns undef. I belived this to be good style and know that many built in functions do this.

However I encounted some problems with this and could do with your opinions on where I'm going wrong. The following code will demonstrate whats been happening.

&mysub2(mysub1); sub mysub1{ #normally returns an array. #on error return undef; } sub mysub2{ my @array = @_; unless(@array){ print "Array is not defined" #Expected out come }else{ print "Exists"; } }
I expected "Array is not defined" but get "Exists". I've tried using defined but -w told me that this is depricated for arrays. So why am I getting this unexpected result?

Replies are listed 'Best First'.
Re: sub returning undef
by BrowserUk (Patriarch) on May 24, 2004 at 14:38 UTC

    Have your sub return the empty list return (); or even (someways better) just return; for the error case. Then your array will be empty.

    undef is a value. For example,  my @array = (undef) x 5; print scalar @array; will print 5.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
Re: sub returning undef
by Abigail-II (Bishop) on May 24, 2004 at 15:01 UTC
    sub never return arrays. They return lists. If you do return undef a list of one element is returned. If you assign that to a scalar, the scalar will have the undefined value. If you assign it to an array, you get an array with one element, that element being undef. It's not any different from return "feebleprops".

    What is special cased is return;, that is, a return without arguments. In scalar context, that will return an undefined value - in list context, it will return an empty list. This is done especially to help in cases you are using.

    Abigail

      sub never return arrays. They return lists.

      A sub never returns an array _directly_, but it can return arrays by reference, along with anything else it wants to return, in its list of return values.

      The OP may have meant that the sub returns a list of whatevers, or he might have meant that it returns an array reference. It's hard to be certain since he only gave us a possibly-misleading comment for that case and focused on the error case where he returns undef. My guess is, he hasn't _written_ the non-error case yet and hasn't put a lot of thought into how it returns, but that's only a guess.


      ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
        A sub never returns an array _directly_, but it can return arrays by reference, along with anything else it wants to return, in its list of return values.
        Well, duh. That's like responding to someone who says "you can't make trees with a camera, just pictures" with "but you can make a picture of a tree!".

        The whole problem of the OP deals with the fact subs return lists, not arrays. The fact that a list element can be a reference to an array is an interesting observation in its own right - but not for this discussion.

        The OP may have meant that the sub returns a list of whatevers, or he might have meant that it returns an array reference.
        The code never uses references. Both the comment and the code show that the OP expected @array to be empty. It's pretty clear to me what the OP expected, and where the OP went wrong.

        Abigail

'use strict', debugger, Data::Dumper
by TomDLux (Vicar) on May 24, 2004 at 14:43 UTC

    WhenI looked at your code, I wondered that you didn't have parentheses when you call mysub1, but it slipped past me all the same, until I did what you should have done, run the code in the debugger.

    &mysub2(mysub1) invokes mysub2 with the text 'mysub1'; so @array is not empy.

    If you used

    use strict;

    as you should, you would have been provided the warning

    Bareword "mysub1" not allowed while "strict subs" in use at <file, lin +e number>

    Even without that warning, if you're confused that mysub2() is following the wrong path, the obvious thing to do is to find out what @array DOES contain, since it doesn't contain what you expect it to. You could print out what @_ contains at the routine entrty point, in which situation Data::Dumper is your friend.

    use Data::Dumper; sub mysub2 { print STDERR Dumper( \@_ ), "\n"; my @array = @_;

    will let you see things are not as you thought.

    Or you could use your debugger. I prefer debugging from emacs (M-x perldb) but not everyone wants to spend the time to learn to use emacs. So use perl -d myscript, then type a letter 's' to 'single-step' into the mysub1() routine. "WOW! What are we doing in mysub2()?". Seeing the code elsewhere than you expected does a lot to guide your debugging ... :-)

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

Re: sub returning undef
by Stevie-O (Friar) on May 24, 2004 at 14:36 UTC
    One problem I see is that 'undef' is an array of one element.

    You should return an empty list: (). That will be treated as false by all conditionals (if unless while until).

    --Stevie-O
    $"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc

        It would be more appropriate to die on error, and expect the calling code to trap it using:

        eval { # calls go here }; if ($@) { # exception handling here }
Re: sub returning undef
by Happy-the-monk (Canon) on May 24, 2004 at 14:38 UTC

    my @array = @_;

    There's your array, even if  $array[0]   yields  undef, @array   still is a defined array with one single element.

    Test for  $_[0]   being  undef, before you create another array.

Re: sub returning undef
by hardburn (Abbot) on May 24, 2004 at 14:41 UTC

    Your code depends completely on how mysub2 is called. If you pass an argument, then mysub2 will show the array being defined. Remember that $foo->mysub2 does pass an argument.

    ----
    send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.

Re: sub returning undef
by adamk (Chaplain) on May 24, 2004 at 18:53 UTC
    Perl is filled with people offering the best way to do things, often correctly, and sometimes totally not what you expect.

    But since variety is the spice of life...

    There are three reasonably cohesive ways to return a list, depending on what you are doing one of them should be relevant.

    Return normally as a list
    The original way is to return the data as a list (returning an array does this), and for the error case just 'return', gives you 'false' in both list and scalar context, the null array in the case of a list context, and undef in scalar context. This is the simplest, but when you want to also signal an error, suffers from tricky testing. In list form, () == error, which can suck when you legally return a null array. In scalar context, well... you only get the number anyways and not the list

    You also get similar problems when you 'return undef', as undef returns in list context as a single element array with an undef in it, which is probably not what you REALLY want anyways. And what if a single undef element is a legal return value?

    Exceptions
    Secondly, we get the exception method, which in perl is essentially "die"ing with the error message. You might use formal exceptions, but they just die underneath. Very clean as you don't have to test for errors everywhere, but if you don't want to be eval/try'ing all the time, or the 'policy' for the code doesn't not allow to use exceptions everywhere, this can get nasty.

    Return by reference
    My personal favourite, and I suspect the best answer in this situation, return just return the list by reference.

    &mysub2(mysub1); sub mysub1{ # Returning something return \@data; # on error return undef; } sub mysub2{ my $result = @_; unless($result){ print "Array is not defined" #Expected out come }else{ print "Exists"; } }
    You can then continue as normal.

    I actually do something else, where I return defined but false for a null list, which can come in handy for something like

    my $rv = getsomething(); die "Error while getting something" unless defined $rv; die "We did not find anything" unless $rv; print "Found " . scalar(@$rv) . " thing(s)\n";
    Anyway, I suspect that's something like what you want.

    Of course, if you DON'T return an error, I prefer to just return as a list.

    For suggestions on a comprehensive return value policy that effectively covers all possible combinations of return value and error(or not), you might like to see http://ali.as/devel/code.html#6, part of my code style policy for myself and my company.
      I have a question on that notion of returning the list by reference. Would that get you into trouble, if the list you were trying to return were in a variable local to the routine doing the returning? In that case, you're providing a reference to something that is about to wink out of existence, right? Or do I misunderstand what you're saying or how it works? (I don't mean to brag, but my ignorance is vast.)
        Well, in the 'local' sense of local, I'm not sure. You should be using the 'local' keyword only to temporarily overload some global variable ( mainly anyway ).

        In the 'my' sense, which is really 'lexical' I believe, no.

        By returning by reference, you've added a second reference to the same data. The original dissapears, leaving you with 1 again. The data won't be nuked until you get to zero references to the data.
Re: sub returning undef
by qq (Hermit) on May 24, 2004 at 22:28 UTC

    I have a sub which if all goes well returns an array but if a error is encounted returns undef. I belived this to be good style and know that many built in functions do this.

    Abigail-II provided the answer, but its getting a bit obscured. Its not good style to return undef because if its assigned to an array you get a one element list. Its better style to just return. Because that is shorthand for:

    wantarray ? () : undef;

    Which is what you almost always want

    qq

      Unless of course the method can legally return a null list, in which case it isn't :)
Re: sub returning undef
by jonadab (Parson) on May 24, 2004 at 15:16 UTC
    my @array = @_;

    What do you mean, exactly, when you say that mysub1 returns an array? If it returns an anonymous array, then the assignment above should read something like

    my @array = @{shift@_};
    As it stands now, not only does the code not do what you want in the error case, it won't do what you want in the case where an array is returned either.


    ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
Re: sub returning undef
by orderthruchaos (Scribe) on May 24, 2004 at 17:50 UTC
    I think the answer to your question is in the many responses you've already received, but none of the answers are that clear to me... The problem seems to be your method of calling the second subroutine. First off, I'm assuming that you meant

    mysub2(mysub1());

    mysub1() will return undef. The problem is, when you pass undef directly to mysub2(...), @_ becomes an array of length 1, with the first (and only) element begin undef. Instead, try this:

    defined mysub1() ? "Exists" : "Array is not defined";

Re: sub returning undef
by tilly (Archbishop) on May 25, 2004 at 15:13 UTC
    Which built-in functions return arrays but return undef on error?

    I both would not recommend that style, and strongly suspect that you're misunderstanding something basic about the behaviour of those functions.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://355922]
Approved by Happy-the-monk
Front-paged by Roy Johnson
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (2)
As of 2024-04-20 03:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found