isakbob
isakbob

Reputation: 1549

How do I prevent the first argument in a subroutine from being absorbed into "@_" in perl?

Background

I have two subroutines that output a prompt. One is a facade subroutine and another is the main subroutine as shown below:

sub facade(@)
{
    my ($prompt) = @_;
    return main("FLAG", $prompt);
}
sub main($@)
{
    my ($flags) = shift;
    my ($prompt) = @_;
    ...<functionality to print a menu prompt>...
}

Behavior

What I want to happen is to output something like the menu below:

Choose an option

X) Exit

1) Green

2) Blue

3) Red

4) Purple (only if "FLAG" is passed in)

What actually happens is the following:

Choose an option

X) Exit

1) Green

2) Blue

3) Red

4) FLAG

This means that the first argument is for some reason absorbed into the "@" itself and not into the logic of my function which says "if this flag exists, output a 4th option". This leads to my question:

Question

How do I prevent the first "$" argument in a subroutine from being absorbed into "@_"?

Upvotes: 0

Views: 169

Answers (1)

ikegami
ikegami

Reputation: 386461

Your question isn't very clear. I think you have a sub that has a required parameter ($prompt) and one optional parameter ($flag), and that you're basically asking how to implement that.

It's easiest if optional parameter come after required ones.

sub main($;$) {
    my ($prompt, $flag) = @_;

    ...
    if ($flag) { ... }
    ...
}


main($prompt);     # $flag = undef, which is false.
main($prompt, 0);  # $flag = 0,     which is false.
main($prompt, 1);  # $flag = 1,     which is true.

The above will assign undef to $flag if only one argument was provided. You could evaluate @_ in scalar context to get the number of arguments provided to check if $flags was provided, but it's not necessary here because undef is a good default.


If a sub accepts multiple options, it's probably best to provide them by name as follows:

sub main($%) {
    my ($prompt, %opts) = @_;

    ...
    if ($opts{purple}) { ... }
    ...
}


main($prompt);
main($prompt, purple => 1);

Note there are problems to using prototypes (including the fact that they can be silently ignored), so you should probably avoid using them even though I left them in.

Upvotes: 4

Related Questions