sub returning nothing

Discussion in 'Perl Misc' started by Gunnar Strand, Jun 8, 2004.

  1. Hi,

    IANAPG (I Am Not A Perl Guru), but I found something which got me a
    little worried. This has probably been discussed ad nauseum, but I
    haven't found anything about it in the FAQ. sub's returning nothing
    can be dangerous in some contexts. Consider this code:

    #!/usr/bin/perl
    use strict;
    use warnings;

    sub isok {
    if ( $_[0] ) {
    print "Ok\n";
    } else {
    print "Nok\n";
    }
    }

    sub myvoid {
    }

    isok( myvoid(), 1 );
    isok( ! myvoid(), 1 );

    This script will print

    Ok
    Ok

    and not any 'Nok'. I assume that's because 'nothing' is magically
    removed from @_, leaving only the '1', right? I am trying out
    the Test::Unit suite and had an empty sub in the code under test
    while using assert in my test case, and all tests passed:

    $self -> assert( $target -> the_test(), "Test OK" );
    $self -> assert( ! $target -> the_test(), "Test NOK" );

    IMHO, it would have been nice if perl could have issued some kind
    of warning, since relying on 'nothing' as a return value seems...
    well, not-so-common. Maybe perl is making heavy use of it internally?

    Regards,

    /Gunnar
     
    Gunnar Strand, Jun 8, 2004
    #1
    1. Advertising

  2. On Tue, 8 Jun 2004, Gunnar Strand wrote:

    >sub isok {
    > if ( $_[0] ) {
    > print "Ok\n";
    > } else {
    > print "Nok\n";
    > }
    >}
    >
    >sub myvoid {
    >}
    >
    >isok( myvoid(), 1 );
    >isok( ! myvoid(), 1 );
    >
    >This script will print
    >
    >Ok
    >Ok
    >
    >and not any 'Nok'. I assume that's because 'nothing' is magically
    >removed from @_, leaving only the '1', right? I am trying out


    Because isok() isn't enforcing any calling context on its arguments,
    myvoid() is called in list context (since it's in the argument list to a
    function), and nothingness in list context is (), and empty list.

    --
    Jeff Pinyan RPI Acacia Brother #734 RPI Acacia Corp Secretary
    "And I vos head of Gestapo for ten | Michael Palin (as Heinrich Bimmler)
    years. Ah! Five years! Nein! No! | in: The North Minehead Bye-Election
    Oh. Was NOT head of Gestapo AT ALL!" | (Monty Python's Flying Circus)
     
    Jeff 'japhy' Pinyan, Jun 8, 2004
    #2
    1. Advertising

  3. Gunnar Strand <> writes:

    > Hi,
    >
    > IANAPG (I Am Not A Perl Guru), but I found something which got me a
    > little worried. This has probably been discussed ad nauseum,


    Yes I can recall one really nausiating discussion of this.

    > but I
    > haven't found anything about it in the FAQ. sub's returning nothing
    > can be dangerous in some contexts. Consider this code:
    >
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    >
    > sub isok {
    > if ( $_[0] ) {
    > print "Ok\n";
    > } else {
    > print "Nok\n";
    > }
    > }
    >
    > sub myvoid {
    > }


    That is not a subroutine returning nothing.

    That is an empty function.

    In a list context an empty function retunrns its arguments.

    In a scalar context it returns undef.

    How ever I wouldn't consider this to be defined bevaviour. I would be
    inclined to consider the behaviour of an empty function wrt what it
    returns to be undefined.

    So let us instead consider a function that returns nothing.

    sub myvoid {
    return;
    }


    > isok( myvoid(), 1 );
    > isok( ! myvoid(), 1 );
    >
    > This script will print
    >
    > Ok
    > Ok
    >
    > and not any 'Nok'. I assume that's because 'nothing' is magically
    > removed from @_, leaving only the '1', right?


    No magic. If you call a function in a list context and it returns
    'nothing' then nothing is an empty list. If you append a 1 to an
    emplt list you get a single elemement list containing the value 1.

    > I am trying out
    > the Test::Unit suite and had an empty sub in the code under test
    > while using assert in my test case, and all tests passed:
    >
    > $self -> assert( $target -> the_test(), "Test OK" );
    > $self -> assert( ! $target -> the_test(), "Test NOK" );
    >
    > IMHO, it would have been nice if perl could have issued some kind
    > of warning, since relying on 'nothing' as a return value seems...
    > well, not-so-common.


    I'm affraid that calling functions in a list context is common in
    perl.
     
    Brian McCauley, Jun 8, 2004
    #3
  4. Brian McCauley <> writes:

    > Gunnar Strand <> writes:
    >
    > > Hi,
    > >
    > > IANAPG (I Am Not A Perl Guru), but I found something which got me a
    > > little worried. This has probably been discussed ad nauseum,

    >
    > Yes I can recall one really nausiating discussion of this.


    Sorry, hit send too soon before I looked up the thread on Google...

    http://groups.google.com/groups?threadm=atqp0b$246$


    --
    \\ ( )
    . _\\__[oo
    .__/ \\ /\@
    . l___\\
    # ll l\\
    ###LL LL\\
     
    Brian McCauley, Jun 8, 2004
    #4
  5. Brian McCauley wrote:
    > Gunnar Strand <> writes:

    [...]
    >>sub myvoid {
    >>}

    >
    >
    > That is not a subroutine returning nothing.
    >
    > That is an empty function.
    >
    > In a list context an empty function retunrns its arguments.


    It returns an empty list in a list context according to perlmod,
    and perl -e 'sub a{};print a(1, 2, 3)' prints nothing.

    > In a scalar context it returns undef.
    >
    > How ever I wouldn't consider this to be defined bevaviour. I would be
    > inclined to consider the behaviour of an empty function wrt what it
    > returns to be undefined.
    > So let us instead consider a function that returns nothing.
    >
    > sub myvoid {
    > return;
    > }
    >
    >>isok( myvoid(), 1 );
    >>isok( ! myvoid(), 1 );
    >>
    >>This script will print
    >>
    >>Ok
    >>Ok
    >>
    >>and not any 'Nok'. I assume that's because 'nothing' is magically
    >>removed from @_, leaving only the '1', right?

    >
    >
    > No magic. If you call a function in a list context and it returns
    > 'nothing' then nothing is an empty list. If you append a 1 to an
    > emplt list you get a single elemement list containing the value 1.


    Thanks for the clarifaction. I didn't think about the list
    context for the sub arguments.

    >>I am trying out
    >>the Test::Unit suite and had an empty sub in the code under test
    >>while using assert in my test case, and all tests passed:
    >>
    >>$self -> assert( $target -> the_test(), "Test OK" );
    >>$self -> assert( ! $target -> the_test(), "Test NOK" );
    >>
    >>IMHO, it would have been nice if perl could have issued some kind
    >>of warning, since relying on 'nothing' as a return value seems...
    >>well, not-so-common.

    >
    >
    > I'm affraid that calling functions in a list context is common in
    > perl.


    Agreed. But it is going to make it more difficult to write test
    cases for methods erroneously using return; (or empty) instead of
    a valid value, as some tests will have to create the needed
    context (or at least when using Test::Unit::TestCase.)

    Thanks for the link to the discussion, that was interesting reading.

    Cheers,

    /Gunnar
     
    Gunnar Strand, Jun 8, 2004
    #5
  6. Gunnar Strand <> writes:

    > Brian McCauley wrote:
    > > Gunnar Strand <> writes:

    > [...]
    > >>sub myvoid {
    > >>}

    > > That is not a subroutine returning nothing.
    > > That is an empty function.
    > > In a list context an empty function retunrns its arguments.

    >
    > It returns an empty list in a list context according to perlmod,
    > and perl -e 'sub a{};print a(1, 2, 3)' prints nothing.


    You are right, it does in 5.8. I was unaware that it has changed.

    > > How ever I wouldn't consider this to be defined bevaviour. I
    > > would be inclined to consider the behaviour of an empty function
    > > wrt what it returns to be undefined.


    Which, of course, is now bourne out to be very good advice wrt 5.6
    because the behaviour in 5.8 is indeed different.

    You say the new behaviour is documented in perlmod? I think you meant
    perlsub. :)

    --
    \\ ( )
    . _\\__[oo
    .__/ \\ /\@
    . l___\\
    # ll l\\
    ###LL LL\\
     
    Brian McCauley, Jun 9, 2004
    #6
  7. Gunnar Strand

    Anno Siegel Guest

    Brian McCauley <> wrote in comp.lang.perl.misc:
    > Gunnar Strand <> writes:
    >
    > > Brian McCauley wrote:
    > > > Gunnar Strand <> writes:

    > > [...]
    > > >>sub myvoid {
    > > >>}
    > > > That is not a subroutine returning nothing.
    > > > That is an empty function.
    > > > In a list context an empty function retunrns its arguments.

    > >
    > > It returns an empty list in a list context according to perlmod,
    > > and perl -e 'sub a{};print a(1, 2, 3)' prints nothing.

    >
    > You are right, it does in 5.8. I was unaware that it has changed.


    It doesn't for me in 5.8.1, that is, it prints "123". (I'll check
    5.8.3 later). I cannot imagine that an incompatible change like this
    would be made. Could some shell deviltry be obscuring the output?

    > > > How ever I wouldn't consider this to be defined bevaviour. I
    > > > would be inclined to consider the behaviour of an empty function
    > > > wrt what it returns to be undefined.

    >
    > Which, of course, is now bourne out to be very good advice wrt 5.6
    > because the behaviour in 5.8 is indeed different.
    >
    > You say the new behaviour is documented in perlmod? I think you meant
    > perlsub. :)


    I can't find the *old* (and, I suspect, still current) behavior described
    in the corresponding version of perldoc, and I was never aware of it
    until now. (Speak of not knowing about fundamental language details...)
    It could be taken as a consequence of the "last expression evaluated"
    rule, though the argument list is nowhere visibly evaluated in the sub.

    Anno
     
    Anno Siegel, Jun 9, 2004
    #7
  8. Anno Siegel wrote:
    > Brian McCauley <> wrote in comp.lang.perl.misc:
    >
    >>Gunnar Strand <> writes:
    >>
    >>
    >>>Brian McCauley wrote:
    >>>
    >>>>Gunnar Strand <> writes:
    >>>
    >>>[...]
    >>>
    >>>>>sub myvoid {
    >>>>>}
    >>>>
    >>>>That is not a subroutine returning nothing.
    >>>>That is an empty function.
    >>>>In a list context an empty function retunrns its arguments.
    >>>
    >>>It returns an empty list in a list context according to perlmod,
    >>>and perl -e 'sub a{};print a(1, 2, 3)' prints nothing.

    >>
    >>You are right, it does in 5.8. I was unaware that it has changed.

    >
    >
    > It doesn't for me in 5.8.1, that is, it prints "123". (I'll check
    > 5.8.3 later). I cannot imagine that an incompatible change like this
    > would be made. Could some shell deviltry be obscuring the output?
    >


    I am using v5.8.4 built for i386-linux-thread-multi, so it
    sounds like it have changed very recently.

    >>>>How ever I wouldn't consider this to be defined bevaviour. I
    >>>>would be inclined to consider the behaviour of an empty function
    >>>>wrt what it returns to be undefined.

    >>
    >>Which, of course, is now bourne out to be very good advice wrt 5.6
    >>because the behaviour in 5.8 is indeed different.
    >>
    >>You say the new behaviour is documented in perlmod? I think you meant
    >>perlsub. :)

    >
    >
    > I can't find the *old* (and, I suspect, still current) behavior described
    > in the corresponding version of perldoc, and I was never aware of it
    > until now. (Speak of not knowing about fundamental language details...)
    > It could be taken as a consequence of the "last expression evaluated"
    > rule, though the argument list is nowhere visibly evaluated in the sub.


    Brian's correct, it's in the perlsub page (mental lapse on
    my part :).

    Regards,

    /Gunnar
     
    Gunnar Strand, Jun 9, 2004
    #8
  9. Also sprach Gunnar Strand:

    > Anno Siegel wrote:
    >> Brian McCauley <> wrote in comp.lang.perl.misc:
    >>
    >>>Gunnar Strand <> writes:


    >>>>It returns an empty list in a list context according to perlmod,
    >>>>and perl -e 'sub a{};print a(1, 2, 3)' prints nothing.
    >>>
    >>>You are right, it does in 5.8. I was unaware that it has changed.

    >>
    >>
    >> It doesn't for me in 5.8.1, that is, it prints "123". (I'll check
    >> 5.8.3 later). I cannot imagine that an incompatible change like this
    >> would be made. Could some shell deviltry be obscuring the output?
    >>

    >
    > I am using v5.8.4 built for i386-linux-thread-multi, so it
    > sounds like it have changed very recently.


    This appears to have been changed in 5.8.2. 5.8.1 is the last release
    where empty functions return their arguments for me.

    Tassilo
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
     
    Tassilo v. Parseval, Jun 9, 2004
    #9
  10. "Tassilo v. Parseval" <> writes:

    > Also sprach Gunnar Strand:
    >
    > > Anno Siegel wrote:
    > >> Brian McCauley <> wrote in comp.lang.perl.misc:
    > >>
    > >>>Gunnar Strand <> writes:

    >
    > >>>>It returns an empty list in a list context according to perlmod,
    > >>>>and perl -e 'sub a{};print a(1, 2, 3)' prints nothing.
    > >>>
    > >>>You are right, it does in 5.8. I was unaware that it has changed.
    > >>
    > >> It doesn't for me in 5.8.1, that is, it prints "123". (I'll check
    > >> 5.8.3 later). I cannot imagine that an incompatible change like this
    > >> would be made.


    I don't think any sane person would claim that the old behaviour was
    defined so I don't really see that compatability is an issue.

    > > I am using v5.8.4 built for i386-linux-thread-multi, so it
    > > sounds like it have changed very recently.

    >
    > This appears to have been changed in 5.8.2. 5.8.1 is the last release
    > where empty functions return their arguments for me.


    But, strangely, 5.8.2 is not the first (even) release where empty
    functions don't return their arguments. They didn't in 5.8.0 either.

    --
    \\ ( )
    . _\\__[oo
    .__/ \\ /\@
    . l___\\
    # ll l\\
    ###LL LL\\
     
    Brian McCauley, Jun 9, 2004
    #10
  11. Gunnar Strand

    Ben Morrow Guest

    Quoth Gunnar Strand <>:
    > Brian McCauley wrote:
    > > Gunnar Strand <> writes:


    <snippage:

    sub isok {
    print $_[0] ? 'OK' : 'NOK';
    print "\n";
    }

    sub void {
    return;
    }

    now isok(void, 1) prints 'OK' not 'NOK'

    >


    > >>IMHO, it would have been nice if perl could have issued some kind
    > >>of warning, since relying on 'nothing' as a return value seems...
    > >>well, not-so-common.

    > >
    > >
    > > I'm affraid that calling functions in a list context is common in
    > > perl.

    >
    > Agreed. But it is going to make it more difficult to write test
    > cases for methods erroneously


    It is not erroneous. It is often necessary: if you wish a function to
    return false in list context, it must return the empty list.

    > using return; (or empty) instead of
    > a valid value, as some tests will have to create the needed
    > context (or at least when using Test::Unit::TestCase.)


    I'm not quite understanding your usage of isok... AFAICS, isok takes one
    argument, and you are calling it with two; so I wouldn't be surprised
    when it doesn't do what you expect.

    isok void;

    correctly prints 'NOK';

    isok 1 == void;

    correctly prints 'NOK' as well.

    I will assume you're not being stupid :), and that in fact your isok
    function is more like:

    sub isok {
    print +( $_[0] ? 'ok' : 'not ok' ), " # $_[1]\n";
    }

    and your problem is that

    isok void, 'testing void function';

    prints 'ok' not 'not ok'. The answer here is that isok should have been
    prototyped with ($$): in that case, the first arg would be evaluated in
    scalar context, and would have been 'undef' not '()', and it would have
    worked correctly.

    If for some reason you don't wish to use prototypes then you must do the
    work of adding scalar() where necessary yourself.

    Ben

    --
    If you put all the prophets, | You'd have so much more reason
    Mystics and saints | Than ever was born
    In one room together, | Out of all of the conflicts of time.
    The Levellers, 'Believers'
     
    Ben Morrow, Jun 9, 2004
    #11
  12. Ben Morrow wrote:
    > Quoth Gunnar Strand <>:
    >
    >>Brian McCauley wrote:
    >>
    >>>Gunnar Strand <> writes:

    >

    [snip]

    >>>I'm affraid that calling functions in a list context is common in
    >>>perl.

    >>
    >>Agreed. But it is going to make it more difficult to write test
    >>cases for methods erroneously

    >
    >
    > It is not erroneous. It is often necessary: if you wish a function to
    > return false in list context, it must return the empty list.


    Of course, but in this case I was writing a test case for a sub
    which was expected to return a scalar, so here it was in fact
    erroneous. I just didn't expect the result I got.

    >>using return; (or empty) instead of
    >>a valid value, as some tests will have to create the needed
    >>context (or at least when using Test::Unit::TestCase.)

    >
    >
    > I'm not quite understanding your usage of isok... AFAICS, isok takes one
    > argument, and you are calling it with two; so I wouldn't be surprised
    > when it doesn't do what you expect.
    > isok void;
    >
    > correctly prints 'NOK';
    >
    > isok 1 == void;
    >
    > correctly prints 'NOK' as well.
    >
    > I will assume you're not being stupid :), and that in fact your isok
    > function is more like:
    >
    > sub isok {
    > print +( $_[0] ? 'ok' : 'not ok' ), " # $_[1]\n";
    > }
    >


    Good point, I should have used the second argument of isok in my
    example for clarity. Thanks for your confidence, but sometimes I
    wonder :)

    > and your problem is that
    >
    > isok void, 'testing void function';
    >
    > prints 'ok' not 'not ok'. The answer here is that isok should have been
    > prototyped with ($$): in that case, the first arg would be evaluated in
    > scalar context, and would have been 'undef' not '()', and it would have
    > worked correctly.


    Unfortunately what you are suggesting will not work since I am using
    Test::Unit::TestCase::assert() (as isok), which can accept either one
    or more arguments, so it has no chance of telling which way it was
    called.

    > If for some reason you don't wish to use prototypes then you must do the
    > work of adding scalar() where necessary yourself.


    Yes, I used the assert( myvoid() || '', "Function failed" ) trick I saw
    in the thread Brian posted about this issue. It is just that a day
    will come when I forget to add the scalar context and think my sub is
    working hard, while it is actually in a coma at the hospital because I
    didn't give it a brain.

    Regards,

    /Gunnar
     
    Gunnar Strand, Jun 9, 2004
    #12
  13. Gunnar Strand

    Ben Morrow Guest

    Quoth Gunnar Strand <>:
    > Ben Morrow wrote:
    > >
    > > I will assume you're not being stupid :), and that in fact your isok
    > > function is more like:
    > >
    > > sub isok {
    > > print +( $_[0] ? 'ok' : 'not ok' ), " # $_[1]\n";
    > > }
    > >

    >
    > Good point, I should have used the second argument of isok in my
    > example for clarity. Thanks for your confidence, but sometimes I
    > wonder :)
    >
    > > and your problem is that
    > >
    > > isok void, 'testing void function';
    > >
    > > prints 'ok' not 'not ok'. The answer here is that isok should have been
    > > prototyped with ($$): in that case, the first arg would be evaluated in
    > > scalar context, and would have been 'undef' not '()', and it would have
    > > worked correctly.

    >
    > Unfortunately what you are suggesting will not work since I am using
    > Test::Unit::TestCase::assert() (as isok), which can accept either one
    > or more arguments, so it has no chance of telling which way it was
    > called.


    Actually, the problem with assert is that it is a method, so it can't be
    prototyped. If it were a function, it should have a prototype of ($;$):
    one scalar and one optional scalar argument.

    If this is bugging you, I would recommend writing call_assert:

    sub call_assert ($$;$) {
    shift->assert(@_);
    }

    > > If for some reason you don't wish to use prototypes then you must do the
    > > work of adding scalar() where necessary yourself.

    >
    > Yes, I used the assert( myvoid() || '', "Function failed" )


    Hmm, that seems a little obscure, when this is precisely what the scalar
    builtin is for:

    $self->assert( scalar myvoid => 'Function failed' );

    Ben

    --
    For the last month, a large number of PSNs in the Arpa[Inter-]net have been
    reporting symptoms of congestion ... These reports have been accompanied by an
    increasing number of user complaints ... As of June,... the Arpanet contained
    47 nodes and 63 links. [ftp://rtfm.mit.edu/pub/arpaprob.txt] *
     
    Ben Morrow, Jun 10, 2004
    #13
  14. Gunnar Strand

    Anno Siegel Guest

    Ben Morrow <> wrote in comp.lang.perl.misc:

    [...]

    > $self->assert( scalar myvoid => 'Function failed' );


    That would autoquote "myvoid'. One pair of () is needed.

    Anno
     
    Anno Siegel, Jun 10, 2004
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben
    Replies:
    2
    Views:
    930
  2. James

    Returning Nothing from Function

    James, Apr 19, 2008, in forum: ASP .Net
    Replies:
    9
    Views:
    358
    sloan
    Apr 21, 2008
  3. Lawrence D'Oliveiro

    Death To Sub-Sub-Sub-Directories!

    Lawrence D'Oliveiro, May 5, 2011, in forum: Java
    Replies:
    92
    Views:
    2,101
    Lawrence D'Oliveiro
    May 20, 2011
  4. Devin Jeanpierre
    Replies:
    2
    Views:
    497
    Devin Jeanpierre
    Feb 14, 2012
  5. furby
    Replies:
    5
    Views:
    159
    furby
    Sep 18, 2006
Loading...

Share This Page