[Bioperl-l] get_nof_contigs returns undef

Heikki Lehvaslaiho heikki.lehvaslaiho at gmail.com
Sat Sep 24 05:11:45 EDT 2005



So the question is how to force list context for a subroutine. This is 
something I've often wondered and have not found a clean solution.


See optional ways to do this within George's function one():

sub one {

    # option 0
    # does not work, because sort() in moose() is defined in scalar context
    return scalar( moose() );

    # option 1
    # does not work, shame because it would be most terse!
    # is there a way to do this?
    #return scalar( @{moose()} );

    # option 2
    # most common, but sort of stupid because it involves a variable
    my @junk = moose();
    return scalar( @junk);

    #option 3
    # performance issues?
    return scalar( map {$_} moose() );

    #option 4
    # we are quickly running out of perl functions 
    # that work in list context...
    return scalar( grep {/./} moose() );

}


 -Heikki


On Friday 23 September 2005 22:50, George Hartzell wrote:
> Wes Barris writes:
>  > [...]
>  > I don't know enough about scalars and array refs to explain this, but
>  > a fix for the above problem is:
>  >
>  > Old Bio/Assembly/Scaffold.pm code:
>  >
>  > sub get_nof_contigs {
>  >      my $self = shift;
>  >      return scalar( $self->get_contig_ids() );
>  > }
>  >
>  > New Bio/Assembly/Scaffold.pm code:
>  >
>  > sub get_nof_contigs {
>  >      my $self = shift;
>  >      my @junk = $self->get_contig_ids;
>  >      return scalar( @junk );
>  > #   return scalar( $self->get_contig_ids() );
>  > }
>
> Ouch.  That makes my head hurt.
>
> I think that the answer's not about "scalars and array ref", but
> what happens when you evaluate things _in a scalar context_, and just
> when that occurs.
>
> Consider the following ridiculous piece of code.
>
>    #!/usr/local/bin/perl -w
>
>    use strict;
>    use warnings;
>
>    print "Without junk: ", one(), "\n";
>    print "With junk: ", two(), "\n";
>
>    sub one {
>     return scalar( moose() );
>    }
>
>    sub two {
>    	my @junk = moose();
>    	return scalar( @junk);
>    }
>
>    sub moose {
>    	my $hash_ref = {};
>
>    	$hash_ref->{a} = 'a';
>    	$hash_ref->{b} = 'b';
>    	$hash_ref->{c} = 'c';
>
>    	return sort keys %{$hash_ref};
>    }
>
>    sub poodle {
>    	my $hash_ref = {};
>
>    	$hash_ref->{a} = 'a';
>    	$hash_ref->{b} = 'b';
>    	$hash_ref->{c} = 'c';
>
>    	if (wantarray()) {
>    		return sort keys %{$hash_ref};
>    	}
>    	else {
>    		return scalar(sort keys %{$hash_ref});
>    	}
>    }
>
>    sub ape {
>    	my $hash_ref = {};
>
>    	$hash_ref->{a} = 'a';
>    	$hash_ref->{b} = 'b';
>    	$hash_ref->{c} = 'c';
>
>    	if (wantarray()) {
>    		return sort keys %{$hash_ref};
>    	}
>    	else {
>    		return scalar(keys %{$hash_ref});
>    	}
>    }
>
> Fire it up in the perl debugger and set a breakpoint in ape (in other
> words, 'b ape').
>
> Now call ape (in other words 'x ape');
>
> Now you should be sitting at the beginning of ape.  Call wantarray by
> hand (in other words 'x wantarray').  **Lesson learned, the perl
> debugger evaluates function calls in a list context** (yeah, it does
> actually say that in the perldebug man page, but who reads *that*?).
> Now step the rest of the way through ape (or just continue, aka 'c')
> and you should see that it prints out the three items in the list
> (a,b,c).
>
> Quit the debugger and restart it on the same file (let's start fresh,
> or just delete the breakpoint you set above).
>
> This time do an 'x $a = ape' (since you're assigning the result of
> calling ape to a scalar variable, it forces it to be evaluated in a
> scalar context et voila, it returns 3.
>
> Now repeat the exercise with sub poodle{} and you'll see that it
> returns the list that you'd expect when you call it in an array
> context, but returns undef when you call it in a scalar context.
>
> Why?
>
> Here's where I'd love a comment from a Perl Language Lawyer, but my
> understanding of what's going on is that you're evaluating the sort()
> function in a scalar context, which Just Doesn't Work.  sort's not set
> up to handle being called in a scalar context and you end up with
> undef.
>
> A less wind-baggy experiment would be to hop into the debugger and
> repeat this it makes sense:
>
>      DB<20> x sort (1, 2, 3)
>    0  1
>    1  2
>    2  3
>      DB<21> x scalar sort (1, 2, 3)
>    0  undef
>      DB<22>
>
>
> Or, to be really brief about it, go look at "perldoc -f sort", where
> the first thing it says is:
>
>     In list context, this sorts the LIST and returns the sorted
>     list value.  In scalar context, the behaviour of "sort()" is
>     undefined.
>
> Then look at the output of "perldoc -f scalar" which starts off with:
>
>     scalar EXPR
>             Forces EXPR to be interpreted in scalar context and returns the
>             value of EXPR.
>
> Probably should-a done that before....
>
> I'll happily buy a beer for the first person who I see *in person* who
> says: "You owe me a beer for making read all of that...".
>
> g.
> _______________________________________________
> Bioperl-l mailing list
> Bioperl-l at portal.open-bio.org
> http://portal.open-bio.org/mailman/listinfo/bioperl-l

-- 
______ _/      _/_____________________________________________________
      _/      _/                      http://www.ebi.ac.uk/mutations/
     _/  _/  _/  Heikki Lehvaslaiho    heikki at_ebi _ac _uk
    _/_/_/_/_/  EMBL Outstation, European Bioinformatics Institute
   _/  _/  _/  Wellcome Trust Genome Campus, Hinxton
  _/  _/  _/  Cambridge, CB10 1SD, United Kingdom
     _/      Phone: +44 (0)1223 494 644   FAX: +44 (0)1223 494 468
___ _/_/_/_/_/________________________________________________________


More information about the Bioperl-l mailing list