[Bioperl-l] [Wg-phyloinformatics] Re: phyloXML weekly report

Chris Fields cjfields at uiuc.edu
Mon Jun 9 14:12:29 EDT 2008

[cross-posting to bioperl-l for archiving]

On Jun 8, 2008, at 11:32 PM, Han, Mira wrote:

> ...
> issues:
> There are a lot of <if/elsif>s when processing the elements,
> I tried to make a hash of function references that point to the  
> member functions,
> But when I tried calling it through the hash, it was giving me an  
> error that I'm trying to call a method on an unblessed object.

I ran into something similar when setting up a few SeqIO modules  
(Bio::SeqIO::gbdriver being on of them) which passed on data chunks to  
method handlers.  It has something to do with how the method is set up  
in the class (package) namespace and how you refer to it.  It's a  
little tricky b/c you run into semantic issues with perl's 'hammered- 
on' OO, but it can be done.

If you call using '$self->{lookup}->{$tag}->(@args)' directly, what  
happens is you can successfully call the method since you are still in  
the proper module namespace.  However, since you aren't calling from  
the invocant ($self) directly but rather from a reference in the  
invocant, it treats the call like a subroutine instead of a method.   
Therefore no invocant is passed as the first argument (you will  
instead get either the first element in @args or 'undef' assigned to  
$self within the method).  Not sure if this is supposed to be a  
feature or a bug.  Regardless, any attempt within the method to do  
something with $self will result in a 'using an unblessed reference'  
or 'not a hash reference'.

There are two solutions, both of which work.  If you have method  
references stored in a hash table in the invocant:

$self->{lookup}->{tag1} = \&foo;
$self->{lookup}->{tag2} = \&bar;

you can grab the actual code reference (checking using 'exists') and  
use it directly on the invocant, but NOT as a code reference.  This  
acts as a symbolic reference, which is allowed for subroutine and  
method calls (I think it's supposed to be DWIM-my):

if (exists $self->{lookup}->{$tag}) {
     my $method = $self->{lookup}->{$tag};
} else {...}

The above also works if you use strings in the lookup table which  
contain the name of the methods (again, symbolic reference):

$self->{lookup}->{tag1} = 'foo';
$self->{lookup}->{tag2} = 'bar';

Alternately, you can pass the invocant in explicitly (which looks  
weird to me, hence my above solution):

if (exists $self->{lookup}->{$tag}) {
     $self->{lookup}->{$tag}->($self, @args);
} else {...}

perl6 fixes a lot of these issues, but of course it won't be out for a  
while longer.

> I'd like to figure out how to do it,
> But before that, is hashing really better than lots of if-elses?

Using a stack of if-elsifs isn't as efficient as a lookup since you  
would test each case in succession (so something that is further down  
the if-elseif test stack would have passed through and failed each  
previous test case before success).  A lookup table would test simply  
based on the existence of a value stored under a key (tag).

An alternative is to use 5.10 features (smart matching and given-when,  
which is like a switch statement), but that will limit usage for those  
still using 5.8.8, which is probably a majority of users, since 5.10  
came out just last December.


> Mira
> On 6/2/08 10:29 AM, "Han, Mira" <mirhan at indiana.edu> wrote:
> Last week (May 26-30):
> 1. made skeleton files for TreeIO:: PhyloEventBuilder,  
> TreeIO::phyloXML, Tree::NodePhyloXML
> 2. managed to connect and load them up but there is a bus error  
> problem.
> I think it's probably due to some of the function calls that I'm  
> making
> That I haven't looked into properly. I'm suspecting it will go away  
> once I properly
> build in the end_element for <clade>
> This week (Jun 2-6):
> 1. implement start_element, and end_element for <phylogeny> and  
> <clade>
> -    start_element: <phylogeny>: add treelevel, <clade>: push data  
> to current_items.
> -    end_element: <phylogeny>: minus treelevel, <clade>: pop data  
> from current_elements, use new() to build node from popped data.
> 2. get rid of that bus error
> 3. TreeIO::phyloXML::Next_tree() : look for element </phylogeny>
> _______________________________________________
> Wg-phyloinformatics mailing list
> Wg-phyloinformatics at nescent.org
> https://lists.nescent.org/mailman/listinfo/wg-phyloinformatics

Christopher Fields
Postdoctoral Researcher
Lab of Dr. Marie-Claude Hofmann
College of Veterinary Medicine
University of Illinois Urbana-Champaign

More information about the Bioperl-l mailing list