« Stupidity | Main | A new look at Mason »

Bitten by prototypes

I just spent the best part of an hour around a problem caused by the behavior of Perl prototypes.

I used the following test case to figure it out:

use Test::More tests => 1;
use Encode qw( encode decode );

sub u8l1 {
  return encode('iso-8859-1', @_);
}

my $ola_u8 = decode('utf8', 'Olá');
my $ola_l1 = encode('iso-8859-1', $ola_u8);
is(u8l1($ola_u8), $ola_l1);

The output of prove x.t is this:

t/x.t .. 1/1 
#   Failed test at t/x.t line 12.
#          got: '1'
#     expected: 'Ol?'
# Looks like you failed 1 test of 1.
t/x.t .. Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests

The got: '1' had me for quite some time. Until I changed the u8l1() helper to this:

sub u8l1 {
  return encode('iso-8859-1', $_[0]);
}

And it just works.

The problem is the definition of the Encode::encode() function. It has a prototype like this:

sub encode($$;$)

So our @_ is interpreted in scalar context, and so evaluates to the number of parameters, 1.

I don't like it at all because it changes the standard Perl behavior of expanding lists. Its action at the distance. The fact that you cannot pass a single element list is also not mentioned in the documentation.

The only really useful use of Perl prototypes is using a & as the initial char, that allows you to write a function that looks like some built-ins like sort or map, that take a anonymous sub as the first parameter.

Contacts

melo@simplicidade.org (XMPP/email)
+351 302 029 050 (voice)
melopt (Skype)

IronMan challenge

Iron Man badge Are you ready to be an Iron Man? Join the challenge and find out! (what is the meaning of this little man?)

Moosaico

Junta-te!

Recent Comments

Powered by Disqus
Creative Commons License
This weblog is licensed under a Creative Commons License.
Powered by
Movable Type 3.2