Dear Nuns and Monks,

after some digging into subroutine signatures I stumbled upon a little problem that seems to be non-existing without signatures: How to distinguish between a missing and an undefined argument? Without signatures it goes straight forward: shift arguments as long as there are any left over. There is no problem distinguishing between non-existing and undefined. See no_sig in the example below.

With signatures, a naive approach would be to check the size of @_, too. This appears to be some kind of illogical to me, see sig_std in the example.

Going one step further, I came to a lexical variable defined inside the signature that is set only in case of a missing argument. This apparently works but I'm not sure if this is indeed valid. The argument and the new variable are named alike to establish a connection between them. See sig_lexical in the example.

Is there a common idiom how to handle such case with signatures? I'm not satisfied with my approaches in the example.

Any other ideas?

#!/usr/bin/perl use v5.12; use Test2::V0; use experimental 'signatures'; sub show ($arg) { defined $arg ? $arg : 'undef'; } # No signature, no check. sub no_sig { my $what = shift; state $data; # Straight forward: shift off first arg if there is any. if (@_) { my $arg = shift; say "$what: ", show $arg; $data = $arg; } else { say "$what: ", show $data; return $data; } } # Standard signature with optional second arg. sub sig_std ($what, $arg=undef) { state $data; # Kind of illogical: there is no obvious connection between @_, it +s # size and $arg. if (@_ >= 2) { say "$what: ", show $arg; $data = $arg; } else { say "$what: ", show $data; return $data; } } # Signature with side effect on missing arg. sub sig_lexical ($what, $arg=(my $no_arg=1, undef)) { state $data; # $arg and $no_arg are (loosely) connected by their names. Howeve +r, # there seems to be no specification about lexical variables # declared within a signature. if (!$no_arg) { say "$what: ", show $arg; $data = $arg; } else { say "$what: ", show $data; return $data; } } pass 'init'; no strict 'refs'; for my $sub (qw(no_sig sig_std sig_lexical)) { # Set to 1 and retrieve: &$sub("$sub setter", 1); is &$sub("$sub getter"), 1, "$sub get 1"; # Set to undef and retrieve: &$sub("$sub setter", undef); is &$sub("$sub getter"), U(), "$sub get undef"; SKIP: { skip "arg check without signature" if $sub =~ /^no/; # Too many arguments: like dies {&$sub("$sub invalid args", 42, 1)}, qr/Too many arguments/, "$sub with three args"; } } done_testing; __DATA__ # Seeded srand with seed '20201227' from local date. ok 1 - init no_sig setter: 1 no_sig getter: 1 ok 2 - no_sig get 1 no_sig setter: undef no_sig getter: undef ok 3 - no_sig get undef ok 4 - skipped test # skip arg check without signature sig_std setter: 1 sig_std getter: 1 ok 5 - sig_std get 1 sig_std setter: undef sig_std getter: undef ok 6 - sig_std get undef ok 7 - sig_std with three args sig_lexical setter: 1 sig_lexical getter: 1 ok 8 - sig_lexical get 1 sig_lexical setter: undef sig_lexical getter: undef ok 9 - sig_lexical get undef ok 10 - sig_lexical with three args 1..10

Greetings,
-jo

$gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$

In reply to Distinguish between missing and undefined arguments with subroutine signatures by jo37

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.