0

I have a sub in Perl that needs to return a list of array refs to fit in with the rest of the package. The problem is that I don't know in advance how many array refs I will generate. My usual method of pushing the array refs that I generate into an array and returning a reference to that doesn't work with the rest of the code, which I can't change without breaking some legacy stuff.

sub subTrackTable {
    my ($self, $experimentName, $subTrackAttr) = @_;

    # return nothing if no subtracks required
    if ($subTrackAttr eq 'no_sub') {
        return;
    }

    # get distinct values for subtrack attr (eg antibody) from db
    my $dbh = $self->dbh();
    my $sh = $dbh->prepare("SELECT DISTINCT * blah sql");
    $sh->execute();
    my @subtrackTable;
    while (my ($term, $value) = $sh->fetchrow_array()) {
        my $subtrack = [':$value', $value];
        push (@subtrackTable, $subtrack);
    }
    $sh->finish();

    # this is hard-coded for one experiment and does what I want
    # Want to loop through @subtrackTable and return a list of all the array refs it contains
    # Returning nested array refs doesn't work with external code
    return ([":H3K4me3", "H3K4me3"],[":H4K20me3", "H4K20me3"]);
}

The problem is that because I am dynamically getting values from a database, I don't know how many there will be. Just returning \@subtrackTable, which would be my usual strategy breaks the rest of the code. If I knew in advance how many there would be I could also do something like

my $a1 = [":$value1", $value1];
my $a2 = [":$value2", $value2];
...
my $an = [":$valuen", $valuen];
return($a1, $a2,...$an);

but I can't see how to make this work with an unknown number of arrayrefs.

Help appreciated!

2
  • Why not returning an arrayref then de-reference it in the caller? Commented Aug 19, 2016 at 11:23
  • Why not just return the list (if that's what the "rest of the code" expects)? I'm trying to understand where the problem arises, how does the "rest of the code" expect its arguments to be provided? Commented Aug 19, 2016 at 11:27

1 Answer 1

2

It looks like you just need to

return @subtrackTable;

Also, this line

my $subtrack = [':$value', $value];

must be changed to use double quotes, like this

my $subtrack = [ ":$value", $value ];
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks - the double quotes were correct in my working copy, this was a typo here. Returning @subtrackTable instead of \@subtrackTable fixed it, but I don't understand why - can you give me an explanation? I don't work in Perl often and sometimes the differences between an arrayref and an array are confusing to me!
It looks like your code is called like this: @values = subTrackTable(...); So your caller expects a list of values which it then stores in an array. Returning @subTrackTable does this. If you return \@subTrackTable then you're returning a single value which is a reference to the array. Then the caller's @values array only gets a single element assigned to it - which isn't what it expects at all.
@Kathryn: If you return an array reference then you are sending back just a single scalar value which points to the array @subtrackTable that you've populated within the subroutine. All the information is still there, but the calling code must expect a reference to be able to use it. Using return @subtrackTable just returns the contents of the array as a list, which corresponds to what your dummy return statement does, which you said works.
Thanks for the explanations. I mostly write Python which just takes care of this stuff under the hood, so it's good to know where I went wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.