iPherian
iPherian

Reputation: 958

Subroutine arguments as key-value pairs without a temp variable

In Perl, I've always liked the key-value pair style of argument passing,

fruit( apples => red );

I do this a lot:

sub fruit {
    my %args = @_;
    $args{apples}
}

Purely for compactness and having more than one way to do it, is there a way to either:

Without:


Attempted

Upvotes: 6

Views: 584

Answers (2)

ikegami
ikegami

Reputation: 385829

You can't perform a hash lookup (${...}{...}) without having a hash. But you could create an anonymous hash.

my $apples  = ${ { @_ } }{apples};
my $oranges = ${ { @_ } }{oranges};

You could also use the simpler post-dereference syntax

my $apples  = { @_ }->{apples};
my $oranges = { @_ }->{oranges};

That would be very inefficient though. You'd be creating a new hash for each parameter. That's why a named hash is normally used.

my %args = @_;
my $apples  = $args{apples};
my $oranges = $args{oranges};

An alternative, however, would be to use a hash slice.

my ($apples, $oranges) = @{ { @_ } }{qw( apples oranges )};

The following is the post-derefence version, but it's only available in 5.24+[1]:

my ($apples, $oranges) = { @_ }->@{qw( apples oranges )};

  1. It's available in 5.20+ if you use the following:

    use feature qw( postderef );
    no warnings qw( experimental::postderef );
    

Upvotes: 7

cdlane
cdlane

Reputation: 41872

If you're more concerned about compactness than efficiency, you can do it this way:

sub fruit {
    print( +{@_}->{apples}, "\n" );

    my $y = {@_}->{pears};

    print("$y\n");
}

fruit(apples => 'red', pears => 'green');

The reason +{@_}->{apples} was used instead of {@_}->{apples} is that it conflicts with the print BLOCK LIST syntax of print without it (or some other means of disambiguation).

Upvotes: 4

Related Questions