Corion has asked for the wisdom of the Perl Monks concerning the following question:
I'm quite fond of using PerlX::Maybe to pass parameters to subroutines if they are there:
GetOptions( 'f' => \my $filename, 'bar' => \my $bar, 'bruce' => \my $batman, 'u' => \my $universe, ); foo( file => $filename, maybe bar => $bar, maybe baz => $batman, maybe universe => $universe, )
The above will invoke foo() with only the hash keys that have a defined value. This is better in the sense that this allows foo() to make a difference between parameter was not passed at all and parameter was passed, but was undef:
sub foo( %options ) { if( ! exists $options{ baz } ) { $options{ baz } = 'Superman'; }; ... }
Now, I'd like to have something similar(ish) to maybe on the receiving side for subroutines and objects, but I'm lacking a good name and a good syntax for it. The idea is to only set a value in a hash if the key does not exist yet. This is different from the // operator, because that one only checks for defined-ness, not for existence.
If we already had full-grown subroutine keyword parameters, this could be written in a declarative way as:
sub foo( :$baz = 'Superman', :$bar, :$file, :$universe='DC' ) { }
(actually, I'm not sure if the above is correct for an invocation foo( baz => undef )).
But we don't have named parameters in the syntax yet, so we have to deparse the parameters ourselves:
sub foo( %options ) { ... }
Let's assume that option is a good name for this (I'm not convinced):
sub option ( $key, $def, $options ) { if( !exists $options->{ $key } ) { $options->{ $key } = $def; } return $options }
Then we could have a syntax like this:
sub foo( %options ) { option baz => 'Superman', option universe => 'DC', \%options; return \%options }
But I'm not entirely happy with this approach for two reasons:
option files => [glob('~/*')], option html => $user_agent->get('https://example.com'),
Test file:
use 5.020; use feature 'signatures'; no warnings 'experimental::signatures'; use Carp 'croak'; sub option ( $key, $def, $options ) { if( !exists $options->{ $key } ) { $options->{ $key } = $def; } return $options } sub required ( $key, $options ) { if( !exists $options->{ $key } ) { croak sprintf 'Need the "%s" option passed in', $key; } return $options } sub foo( %options ) { option baz => 'Superman', option universe => 'DC', \%options; return \%options } sub req( %options ) { required 'run', option baz => 'Superman', \%options; return \%options } use Test2::V0 '-no_srand'; is option('baz' => 'default', {}), { baz => 'default' }, 'Setting a de +fault'; is foo(), { baz => 'Superman', universe => 'DC' }, 'Default values'; is foo(baz => 0), { baz => '0', universe => 'DC' }, 'False value'; is foo(baz => undef), { baz => undef, universe => 'DC' }, 'Undef but p +resent value is kept'; is foo(baz => undef), { baz => undef, universe => 'DC' }, 'Undef but p +resent value is kept'; ok dies { req( baz => 'Wonderwoman' ) }, 'A missing obligatory option +dies'; ok lives { req( run => undef, baz => 'Wonderwoman' ) }, 'Passing the o +bligatory option lives, even if undefined'; #class cfoo 0.01 { # field $baz; # field $universe; # # method foo( $self, %options ) { # option baz => $self->baz, # option universe => $self->universe, # \%options; # # return \%options # } #} #my $f = cfoo->new( baz => 'objSuperman', universe => 'DC' ); #is $f->foo( baz => undef ), { baz => undef, universe => 'meth_DC' }, +'Positional parameters work'; done_testing;
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Existing module for PerlX::Maybe except for hash existence?
by haj (Vicar) on Feb 22, 2025 at 23:23 UTC | |
by haukex (Archbishop) on Feb 25, 2025 at 15:20 UTC | |
by etj (Priest) on Feb 25, 2025 at 18:40 UTC | |
by cavac (Prior) on Feb 24, 2025 at 16:18 UTC | |
by haj (Vicar) on Feb 24, 2025 at 17:53 UTC | |
by ikegami (Patriarch) on Feb 24, 2025 at 18:44 UTC |