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:

  1. It doesn't strike me as overly elegant. I'm happy with it being not overly elegant, but there are some warts:
    • We pass in and modify the %options hash by reference. Alternatively we could do %options = option foo => 'bar', %options;, but that copies the whole hash a lot of times
    • We eagerly evaluate the default values, which might be costly in the case of function calls:
      option files => [glob('~/*')], option html => $user_agent->get('https://example.com'),
  2. There must be something like this on CPAN already

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;


In reply to Existing module for PerlX::Maybe except for hash existence? by Corion

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.