Perl: argument passing weirdness

The project I’m currently working on is using Perl scripts. I usually use Python for scripting, but introducing another programming language didn’t seem like a good idea, so I decided to write in Perl.

At first, I was struck with $all @the %decorators which make the code @$difficult $to @#read. Nothing to do about it.

Next thing, a very strange way of reading function arguments. You don’t define them, all the stuff comes in something with a friendly name of @_ which is basically a lump of arguments. It’s your job to make it useful. And it isn’t necessarily easy to do.

Let me give you an example. I’ll start off with a Python function that prints a list to the screen:

a = ['a', 'b', 'c', 'd']
print a

When executed, it prints this:

['a', 'b', 'c', 'd']

A corresponding Perl code looks like this:

@a = ('a', 'b', 'c', 'd');
print "@a∖n";

And produces:

a b c d

As you can see, Python code is a little cleaner, as it doesn’t have @decorators and you don’t need to surround the list with “all the weird stuff∖n” to get the list on the screen in a comprehensive form.

Let’s get back to our code. Let us write a function that takes a list as an argument and prints it. In Python:

def one_list(list_a):
    print list_a

It’s pretty straightforward. We need to write the name of our function, then the arguments (currently just one) in the brackets and then the function body. The same in Perl:

sub one_list {
    my @list_a = @_;
    print "@list_a∖n";
}

What’s strange here is that there is no way to specify the list of arguments that the function accepts. There’s only the lumpy @_ variable which contains a list that the function was called with. You don’t actually know, how was the function called, because it could be one_list(@a) as well as one_list(‘a’, ‘b’, ‘c’, ‘d’) and you can’t tell any difference in the @_. That’s why I call it a lump.

Now that we have a function which accepts a list, let’s try two lists. With Python, we can just extrapolate what we had before. One more thing in the brackets, voila, two lists ready to use.

def two_lists(list_a, list_b):
    print list_a
    print list_b

What about Perl? Can we extrapolate the one_list function? Perhaps I’m spoiled, but usually as I learn how to declare a function with one argument, I don’t need to learn anything more to write a two-argument one. So, I’ve tried this…

sub two_lists {
    my ($list_a, $list_b) = @_;
    print "@list_a∖n";
    print "@list_b∖n";
}

…no error message. And… somehow, @list_a swallowed the second argument, leaving @list_b empty. The two list were just concatenated somewhere on the way and function sees just one list instead of original two. Ouch.

Finally, a friend brought a solution. It looks like this:

sub two_lists {
    my ($list_a_ref, $list_b_ref) = @_;
    my @list_a = @$list_a_ref;
    my @list_b = @$list_b_ref;
    print "@list_a∖n";
    print "@list_b∖n";
}

What it does, is it reads references to the lists and then uses weird @$ syntax to dereference them, er, make them usable.

In this example, there are additional lines of code that wouldn’t have to be there if… well… never mind.

Whatever the reason, instead of simply declaring a list of arguments, I have to wrestle with @_ and references.

Life with Python was so easy… I think you can now understand this picture (even though it was Perl 5 in the examples):

Perl 6

Programming with Perl looks more like something weird, geeky and obscure. It’s easy to write “Hello, world”, but one you want to write any complex data structure, references and inconsistent syntax will quickly get you down. Since data structures are difficult to handle in Perl, you will tend to write complex procedures, making your program difficult to read and understand and therefore difficult to maintain. It’s the opposite to what Eric Raymond says about handling complexity.

Perl seems to be a quintessence of what I don’t like in programming languages.