Andrew Rodland skribis 2005-11-07 13:30 (-0500):
> If you want to get into personal beliefs, I think that function signatures 
> are 
> such a complexity quagmire -- and that they're line-noise ugly to boot.

The nice thing about signatures is that they let you write what you
mean. This saves you an entire translation from what you mean to some
Perl code that manipulates @_. This translation is hard, and error
prone, as is the code that comes from it.

I think that even without any introduction to the subtleties of
signatures, any newbie with some programming experience will instantly
understand the essence of:

    sub my_join ($sep, [EMAIL PROTECTED]) { 
        foo($sep, @elems);
    }

and

    method connect ($host, $port = 80) { ... }

While this isn't quite so clear:

    sub my_join { 
        my $sep = shift;
        foo($sep, @_); 
    }

    sub connect { 
        croak "..." if @_ < 1;
        croak "..." if @_ > 2;
        my ($host, $port) = @_; 
        $port = 80 if not defined $port; 
        ...
    }

Or let's take this simple example:

    sub convert (:$from, :$to, :$thing) { ... }

That isn't quite "my %args = @_;". Yes, that works, but the only real
way we keep doing it is that the full solution sucks in plain Perl 5:

    sub convert {
        croak "..." if (@_ % 2) != 0;
        my %args = @_;
        croak "..." if not exists $args{from};
        croak "..." if not exists $args{to};
        croak "..." if not exists $args{thing};
        my $from  = delete $args{from};
        my $to    = delete $args{to};
        my $thing = delete $args{thing};
        croak "..." if keys %args;
        ...
    }

before you shout that I'm doing something wrong, yeah, I've been out of
this game for a while. Which only strengthens my point: it's hard to do
it right in Perl 5!

So, the typical answer is: use a module! Good idea, really, but that
still doesn't fix the problem. There are several modules out there that
handle argument parsing, that in practice you need to know the
subtleties of each of them. And none lets you combine scalar and list
context, because only prototypes can do that. I don't have to explain
why prototypes suck, and I think you can guess why combining them with a
parsing module sucks too.

For fun, one example with Params::Check:

    use Params::Check qw(check);

    sub convert {
        croak "..." if (@_ % 2 ) != 0;
        my %args = @_;
        check(
            {
                from  => { required => 1, store => \my $from },
                to    => { required => 1, store => \my $to },
                thing => { required => 1, store => \my $thing },
            },
            \%args,
            1,
        );
        ...
    }

And oh boy, would this all have been VERY different if I wanted to
simulate this instead:

    sub convert (:$from, :$to, :$thing is rw) { ... }

I think the complexity of signatures is much less than that of doing the
same things without them, with the extra benefit that even beginners
will (almost) instantly understand most of it!


Juerd
-- 
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html 
http://convolution.nl/gajigu_juerd_n.html

Reply via email to