Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Checking number of values returned

by jfrm (Monk)
on Feb 08, 2015 at 10:39 UTC ( [id://1115903]=perlquestion: print w/replies, xml ) Need Help??

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

Bald-headed Comrades,

I've read about checking that the number of arguments passed by a subroutine is correct, prototyping and how it shouldn't be necessary. Generally speaking I do check args passed within the code and so that seems right.

However, I regularly change the number of values returned by subroutines and I often seem to make mistakes with this - by overlooking an instance of the calling subroutine or overlooking a return statement. So I would like to find a way or a tool for checking all subroutines across all my PERL files to make sure that the number of values expected matches every instance of the return statement within each routine.

Any ideas? Thanks for any advice.

Replies are listed 'Best First'.
Re: Checking number of values returned
by BrowserUk (Patriarch) on Feb 08, 2015 at 14:39 UTC

    I'd say that unless you habitually and religiously always assign your functions to individual scalars, eg: my( $x, $y, $z ) = yourfunc();, then there is no way to do this check.

    If you assign your function to:

    1. an array: my @vals =  yourFunc();
    2. or a hash: my %hash = yourFunc();
    3. or use it in a for loop: for my $x ( yourFunc() ){
    4. or to map;  ... map{ ... } yourFunc();
    5. or grep;  ... grep{ ... } yourFunc();
    6. or as an arg to any other function: someFunc( 1, 'fred', yourFunc() ); user or built-in;

    then there is no way to know how many values it should return.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
      Well now you make me think about it, I suppose that I do habitually assign my functions to individual scalars. Perhaps this is the XY problem referred to earlier but actually I find that doing it this way makes my code much more understandable so would argue that it's a good thing. Anyway, even if I only did it only 30% of the time, it would still seems to be a valid useful thing to check for those 30% that were checkable...
        Well now you make me think about it, I suppose that I do habitually assign my functions to individual scalars. Perhaps this is the XY problem referred to earlier

        It sounds like the XY problem is that you've come to Perl from another language and haven't yet fully made the transition.

        I have the reverse problem. Every time I use C; I find my self wishing I could return multiple -- and variable numbers of -- values from functions:)

        And the funny thing is that if you always assigned your results to an array, it would be much easier to check the number of returned values:

        my @results = someFunc(); die unless @results == 3; ...

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Checking number of values returned
by LanX (Saint) on Feb 08, 2015 at 16:24 UTC
    Perl is a dynamic language and this kind of static typing with compile time checking belongs to Java or Haskell.

    Theoretically you could do runtime checking by replacing your function with a wrapper in the middle checking

  • the returned values from the original
  • parsing the code of the calling code line.

    The wrapper could be installed by an attribute.

    But I doubt the outcome justifies the effort, cause it'll come with notable performance loss for an unusual case.

    You should rather question your strategy if you're passing around too many positional parameters.

    Smells a bit like an XY problem...

    Cheers Rolf

    PS: Je suis Charlie!

Re: Checking number of values returned
by clueless newbie (Curate) on Feb 08, 2015 at 13:24 UTC
      Thanks for the suggestion. I took a look but seems to be checked params passed rather than values returned so not a solution I fear.
Re: Checking number of values returned
by Anonymous Monk on Feb 08, 2015 at 13:08 UTC

    Interesting question! I'd say that unless all of your return statements take some form of return $one, $two, $three;, that's something you could only do at runtime instead of by looking at the source, as it gets less clear how many values will actually be returned in situations like return @foo; or return bar();.

    How about something like Hook::LexWrap (see also http://www.perladvent.org/2003/3rd/)? I haven't really used it before but it seems like it should be possible to implement a check like you want:

    use Hook::LexWrap 'wrap'; sub my_func { return ("foo") x shift } wrap my_func => post => sub { my $cnt = @{$_[-1]}; # assumes list context! print "Returning $cnt values\n"; }; print my_func(1), "\n"; print my_func(2), "\n"; print my_func(3), "\n"; __END__ Returning 1 values foo Returning 2 values foofoo Returning 3 values foofoofoo

    It may also be worth taking a step back: How many returns do you have per sub? What's the largest number of values per return you have? If you've got a lot of returns per sub, then perhaps your logic is getting a little too complex? And if you have a large number of values per return, then perhaps you could look into returning complex data structures instead, like arrayrefs, hashrefs, or objects?

      > then perhaps you could look into returning complex data structures instead, like arrayrefs, hashrefs, or objects?

      And perhaps if many redundant hashes are passed around, a redesign to OOP is reasonable, where the subs become the methods of the object's data.

      edit

      IOW instead of passing data one is chaining methods.

      Cheers Rolf

      PS: Je suis Charlie!

Re: Checking number of values returned
by Anonymous Monk on Feb 09, 2015 at 11:21 UTC

    There's also PPI, which does a relatively good job of parsing Perl.

    With PPI it should certainly be possible to identify and check that subset of your returns and function calls which take some regular, identifiable form. I'm not (yet) aware of existing code that already does this, but I could be missing something. Maybe one of the many Perl::Critic policies could provide a starting point...

    use PPI; my $doc = PPI::Document->new( \<<'ENDPERL' ); sub foo { return 1, 2, 3 } my ($x, $y, $z) = foo(); ENDPERL use PPI::Dumper; PPI::Dumper->new( $doc, whitespace=>0 )->print; __END__ PPI::Document PPI::Statement::Sub PPI::Token::Word 'sub' PPI::Token::Word 'foo' PPI::Structure::Block { ... } PPI::Statement::Break PPI::Token::Word 'return' PPI::Token::Number '1' PPI::Token::Operator ',' PPI::Token::Number '2' PPI::Token::Operator ',' PPI::Token::Number '3' PPI::Statement::Variable PPI::Token::Word 'my' PPI::Structure::List ( ... ) PPI::Statement::Expression PPI::Token::Symbol '$x' PPI::Token::Operator ',' PPI::Token::Symbol '$y' PPI::Token::Operator ',' PPI::Token::Symbol '$z' PPI::Token::Operator '=' PPI::Token::Word 'foo' PPI::Structure::List ( ... ) PPI::Token::Structure ';'

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2024-03-28 13:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found