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

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

Replies are listed 'Best First'.
Re^3: Distinguish between missing and undefined arguments with subroutine signatures
by jo37 (Curate) on Jan 08, 2021 at 21:46 UTC
    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

        Trying to implement it according to your remarks leads me to something I don't like at all.

        EDIT: See comments in uglier_foo.

        my $missing = sub {...}; # private sub sub ugly_foo ($self, $foo=$missing->(), $bar=$missing->()) { say "foo is missing" if $missing->($foo); say "bar is missing" if $missing->($bar); } # compare with eq sub uglier_foo($self, $foo=MISSING, $bar=MISSING) { # This comes from posting insufficiently tested code at midnight # say "foo is missing" if !$foo || $foo eq MISSING; # say "bar is missing" if !$foo || $foo eq MISSING; say "foo is missing" if $foo && $foo eq MISSING; say "bar is missing" if $bar && $bar eq MISSING; } # slurping sub ugliest_foo ($self, @args) { my ($foo, $foo_missing); if (@args) { $foo = shift @args; } else { $foo_missing = 1; } my ($bar, $bar_missing); if (@args) { $bar = shift @args; } else { $bar_missing = 1; } if (@args) { croak "too many arguments"; } say "foo is missing" if $foo_missing; say "bar is missing" if $bar_missing; }

        So, yes, I stubbornly stick to my solution.

        Greetings,
        -jo

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