in reply to Distinguish between missing and undefined arguments with subroutine signatures

Using LanX's suggestion in Re^3: Distinguish between missing and undefined arguments with subroutine signatures (semipredicate problem), I finally found a practicable solution to my problem.

# Unique catcher for a missing argument use constant MISSING => bless {}, __PACKAGE__ . '::__missing__'; # Helper sub, that either checks its argument against the catcher # or otherwise returns the catcher itself. sub missing { @_ ? $_[0] && $_[0] eq MISSING : MISSING; } # To be used with signatures in various places: sub foo ($self, $val=missing) { if (missing $val) { # getter } else { # setter } }

Thanks, Rolf!

Greetings,
-jo

$gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
  • Comment on Re: Distinguish between missing and undefined arguments with subroutine signatures
  • Download Code

Replies are listed 'Best First'.
Re^2: Distinguish between missing and undefined arguments with subroutine signatures
by LanX (Saint) on Jan 08, 2021 at 19:59 UTC
    Your Welcome! :)

    But I suppose you don't want the sub missing() to be available as method the way ->foo() is?

    And while the MISSING object is a nice workaround for the semi-predicate problem, I still think it's an overkill here.

    Like I said you could just slurp into @val and have the full functionality, with less code:

    use strict; use warnings; use experimental "signatures"; use Carp; { package BLA; sub new ($class,@properties) { return bless {@properties}, $class; } sub foo ($self, @val) { unless (@val){ # getter return $self->{foo} } elsif (@val == 1) { # setter return $self->{foo} = $val[0]; } else { # ERROR local $" = ","; Carp::croak "Too many arguments for method 'BLA->foo(@val) +'"; } } } my $x = BLA->new(foo=>42); warn "getter:", $x->foo; warn "setter:", $x->foo(666); warn "getter:", $x->foo; warn "error:", $x->foo(42,666);

    -*- mode: compilation; default-directory: "d:/tmp/pm/" -*- Compilation started at Fri Jan 8 21:39:32 C:/Perl_524/bin\perl.exe -w d:/tmp/pm/missing_param.pl getter:42 at d:/tmp/pm/missing_param.pl line 31. setter:666 at d:/tmp/pm/missing_param.pl line 32. getter:666 at d:/tmp/pm/missing_param.pl line 33. Too many arguments for method 'BLA->foo(42,666)' at d:/tmp/pm/missing_ +param.pl line 34. Compilation exited abnormally with code 255 at Fri Jan 8 21:39:33

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    updates

    improved code with croak and better error message

      But I suppose you don't want the sub missing() to be available as method the way ->foo() is?

      That doesn't harm at all. Calling $obj->missing just returns false, which is correct :-)

      However, your objection discovered a flaw in my approach. The missing sub needs to be prototyped to go one step further: multiple optional arguments. And then slurping starts hurting :-)

      This leads to:

      #!/usr/bin/perl use v5.16; use warnings FATAL => 'all'; package Foo; use experimental 'signatures'; use constant MISSING => bless {}, __PACKAGE__ . '::__missing__'; sub missing :prototype(;$) { @_ ? $_[0] && $_[0] eq MISSING : MISSING; } sub new ($class) { bless {}, $class; } sub foo ($self, $foo=missing, $bar=missing) { say "foo is missing" if missing $foo; say "bar is missing" if missing $bar; } package main; my $foo = Foo->new; say "none:"; $foo->foo; say "one:"; $foo->foo(1); say "two:"; $foo->foo(1, 2); print "\n"; say 'object foo is not missing' unless $foo->missing; __DATA__ none: foo is missing bar is missing one: bar is missing two: object foo is not missing

      Greetings,
      -jo

      $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
        > And then slurping starts hurting :-)

        ++ for linguistic excellency but not for correctness. ;-)

        Some remarks:

        • you don't need a sub missing() just compare with eq
        • if you really need it make it a private sub with my $missing = sub {...}
        • since constants are implemented as subs, they'll be methods too °
        • slurping @vals can still handle both cases by checking the length
        Anyway, you seem to be very convinced, so good luck and enjoy! :)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        °) maybe consider namespace::clean