http://www.perlmonks.org?node_id=11125794

jo37 has asked for the wisdom of the Perl Monks concerning the following question:

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$