[Bioperl-l] get_nof_contigs returns undef

George Hartzell hartzell at kestrel.alerce.com
Fri Sep 23 17:50:37 EDT 2005


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.


More information about the Bioperl-l mailing list