[Templates] Fun with arrays

Mihai Bazon mihai@bazon.net
Sat, 10 Feb 2007 02:53:48 +0200


Hi folks,

Not sure if this issue was raised before, so here I go.

I have a function like this in a (say "Foo") plugin:

    sub bar {
        my @a;
        # ... compute @a
        return wantarray ? @a : \@a;
    }

And from a template I needed to output some prefix ("Tags: ") and the 
array values separated by commas.  Obviously, if there were no elements 
in the returned array, no output should occur.

I had this:

    [% SET a = Foo.bar; IF a.size > 0 %]
    Tags: [% FOREACH i = a;
        ', ' IF !loop.first;
        i;
        END; %]

To my surprise, when "@a" in that function was an empty array the 
"Tags:" text was present in output.

After some hassling I understood that returning an empty array from a 
function is equivalent to returning undef, which TT interprets as an 
empty string (and empty_string.size == 1 because.. err... that's written 
in the manual but it doesn't make too much sense so I forgot why).

I'm not sure who's at guilt here: Perl, for deciding that an empty array 
means "undef", TT for deciding that a scalar must have .size == 1, or me 
for being dumb enough to make functions that return an array or an 
arrayref depending on how they're called (but let's just say it's too 
late to fix the latter).

A simple solution (for this particular case) is to check "IF a" instead 
of "IF a.size > 0".  Empty strings evaluate to "false" in conditionals, 
so it works fine.  However, it's not an "universal" solution because if 
I have a function that always returns an arrayREF, then the empty array 
will evaluate to "true".

Of course, the definitive solution is "IF a && a.size > 0" but this 
looks ugly to say the least.  So I was thinking to suggest to make TT 
evaluate empty arrays (REF-s, that is) to "false" in conditionals, same 
as it does with empty strings.  Makes sense?

Thanks,
-M.