Subroutine arguments as key-value pairs without a temporary variable

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

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 this, there is a way to either:

  • to access key-value pairs without assigning an @_ hash? That is, in one statement?

  • subroutine arguments automatically become a hash reference, perhaps through a prototype subroutine?

Without:

  • assignment of a temporary variable my %args = @_;

  • when the caller follows the link ie fruit({ apples => red }); purely for aesthetics


Attempt

  • ${%{\@_}}{apples}

    @_ trying to reference @_ , interpret this as a hash of ref and access the value with a key.

    But I get an error that this is not a hash link. (Which is not ^. ^) I am thinking of C, where you can specify pointers, among other things, and avoid explicit remapping.

  • I also tried prototype routines

    sub fruit (%) { ... }

    ... but the arguments are collapsed to @_ , as usual.

+6
source share
2 answers

You cannot perform a hash search ( ${...}{...} ) without a hash. But you can create an anonymous hash.

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

You can also use simplified post-dereference syntax

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

That would be very inefficient. You would create a new hash for each parameter. This is why a named hash is commonly used.

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

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

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

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

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

  • It is available in 5.20+ if you use the following:

     use feature qw( postderef ); no warnings qw( experimental::postderef ); 
+6
source

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} used instead of {@_}->{apples} is that it does not conflict with the print BLOCK LIST print syntax without it (or some other disambiguation tool).

+4
source

All Articles