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

Hi

I'm trying to extend Damians PBP advices for unpacking and then checking arguments using the ternary-operator ...

sub padded { my ($text, $arg_ref) = @_; # Set defaults... # If option given... Use option Else defau +lt my $cols = exists $arg_ref->{cols} ? $arg_ref->{cols} : $DEF_PAG +E_WIDTH; my $filler = exists $arg_ref->{filler} ? $arg_ref-> : $SPACE; # ... etc return $filler x $left . $text . $filler x $right; }

... by using the defined-or operator, which was new in 5.10 long after PBP was published.

It's more concise ... but actually I'm not sure how to handle named arguments¹ so which pattern do you think is better?

*** Unpack Named First

sub unpack_named_first { my ($pos1, $pos2 ,%arg) = @_; # unpack my ($name1, $name2) = @arg{'name1','name2'} $pos1 // die("Missing arg!"); # obligatory $pos2 //= 42; # default $name1 // die("Missing arg!"); # obligatory #$name2 # optional # ...etc }

*** Unpack Named Later

sub unpack_named_later { my ($pos1 ,$pos2 ,%arg) = @_; $pos1 // die("Missing arg!"); $pos2 //= 42; $arg{name1} // die("Missing arg!"); # if you need to unpack hash-args my ($name1,$name2) = @arg{qw/name1 name2/}; # ...etc }

*** Unpack Named On The Fly

sub unpack_named_on_the_fly { my ($pos1 ,$pos2 ,%arg) = @_; $pos1 // die("Missing arg!"); $pos2 //= 42; my $name1 = $arg{name1} // die("Missing arg!"); my $name2 = $arg{name2}; # ...etc }

My intentions are:

1. to have a concise pattern to replace the (alas) missing sub-signatures in perl

2. to follow more DRY practice

3. The patterns should be also usable in parts, i.e. further arg constraints could be extendable later, e.g. using ternaries

4. to have self-documenting code.

5. to be parsable for inspection and/or POD-creation and/or IDE-expansion.

a further extension could be to replace die() with a wrapper called missing(), which uses caller to pretty-print source-line and function-name.

$pos1 // die_miss(); $pos2 // warn_miss();
Personally I tend to the first option to unpack first, even if it's more work to refactor if someone decides later that he needs to unpack %arg which he used directly before, ie. $arg{name}

Cheers Rolf

¹) please don't be confused:

1. at my current project we are not following Damian's advice to use an anonymous hash for named args.

2. testing for existence instead for definedness is such a rare special case that it should be explicitely coded.

Replies are listed 'Best First'.
Re: RFC: New style for argument check in subs
by Jenda (Abbot) on Sep 05, 2012 at 11:30 UTC

    "missing" ne "undefined"!

    An undef may very well be the value you want to specify! There is a big difference between foo({bar => 15, baz => undef}) and foo({bar => 15}) and I would definitely not expect to get the default value of baz in the first case.

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

      As I already said, accepting undef as valid argument is such a special and rare case that it should be covered by another approach. (see footnotes in OP)

      Here using ternaries is far more explicit and shows that a special argument undef is accepted.

      my $a = exists $arg{a} ? $arg{a} : 'else case';

      But I agree that it's better to name the error die('Undefined argument!') instead of 'Missing argument' to avoid such misunderstandings.

      Cheers Rolf

        Not rare at all! Both as unnamed and as named parameter used in DBI + DBD::CSV:

        use DBI; my $dbh = DBI->connect ( "dbi:CSV", # Unnamed, driver undef, # Unnamed, username undef, # Unnamed, password { f_ext => ".csv/r", # Named and defined f_schema => undef, # Named and undefined });

        FWIW all NULL values in a database are refered to through undef, so you'll see a lot of those in both named and unnamed arguments to functions and methods.


        Enjoy, Have FUN! H.Merijn
Re: RFC: New style for argument check in subs
by BrowserUk (Patriarch) on Sep 05, 2012 at 12:59 UTC

    FWIW: For named args -- which I rarely see the need for these days -- to do existence checking, defaulting and reporting of unknowns, I settled on this a long time ago.

    Simple, compact, understandable and efficient, it serves my purposes for the rare occasions I need it.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

    Science is about questioning the status quo. Questioning authority
      I occasionally use similar approaches, but I'm working in an environement which does rarely do parameter checks and if then with long and nested if statements.

      Complicated hashslices are for most of my colleagues completely out of scope.

      As far as I understand your code, everything which doesn't have a default-value must be ignored?

      I think you have a special understanding of "optional".

      UPDATE: But I think I could use this approach for personal use. :)

      Unfortunately you don't show compatible way to check positional arguments.

      Cheers Rolf

        You have a special understanding of optional.

        What a beautifully crafted put-down :)

        My reasoning is: if its allowed, even if it is optional -- in fact especially if it is optional -- it should have a default value. Even if that default value is undef.

        One of the benefits of that, is that it deals with the "actual value is undef" problem. If the explicitly passed value is undef, and you override it to its default which is undef, then ...

        I do remember some discussion around the possibility of using undef to override a default value, but I decided that such usage was rare and obscure enough that if teh occasion arose it was necessary, I'd had code a solution for it above or below the standard mechanism as appropriate.

        I don't mind hand coding a solution for the 1 in 1000 case, if that means the other 999 cases operate in an efficient manner.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

        /blockquote
Re: RFC: New style for argument check in subs
by Anonymous Monk on Sep 05, 2012 at 10:54 UTC

    I'm trying to extend Damians PBP advices for unpacking and then checking arguments using the ternary-operator ...

    Icky :)

    1. to have a concise pattern to replace the (alas) missing sub-signatures in perl

    Sub::Signatures, Method::Signatures

    2. to be follow DRY practice

    Params::Validate?

    3. 4. 5. to be parsable for inspection and/or POD-creation and/or IDE-expansion.

    ??

      * Sub::Signatures,

      use Filter::Simple ???

      are you serious?

      * Method::Signatures

      use base 'Devel::Declare::MethodInstaller::Simple' ???

      are you serious?

      * Params::Validate

      nice but ...

      - overhead by extra sub call

      - parameters are unpacked into %p hash, i.e. you need to type $p{x} to access x adn you'll miss all the benefits of compiletime checks for lexicals like my $x.

      So any serious arguments other than clicking thru CPAN?

      Cheers Rolf

        use Filter::Simple ??? are you serious?

        absolutely, makes things much nicer

        use base 'Devel::Declare::MethodInstaller::Simple' ??? are you serious?

        absolutely, its for those who want sugar but not source filters -- schwern says its reliable

        nice but ... - overhead by extra sub call

        HA! are you serous? You can't be serious :)

        - parameters are unpacked into %p hash, i.e. you need to type $p{x} to access x

        this isn't the only usage, there is validate_pos, and even as Attribute::Params::Validate

        and you'll miss all the benefits of compiletime checks for lexicals like my $x.

        What compile-time checks?

        So any serious arguments other than clicking thru CPAN?

        You're looking for arguments about something? About what?

        Hey look, these are compile-time :) fields, Hash::Util::lock_keys, Sub::NamedParams

        If you're referring to so which pattern do you think is better? to me there really isn't much difference between them -- not that your mission makes sense to me

        Even if I'm typing this stuff myself, I'm fine with

        defined $pos1 or die "missing arg"; defined $pos2 or $pos2 = 42;

        but I wouldn't mix that and  my ($name1,$name2) = @arg{qw/name1 name2/};

        I would use a hash or a flatlist

        Method::Signatures -- yes, I am serious. It's good.

        Method::Signatures::Simple -- yes, I am serious again. It's still good.

        The computer can handle working harder. You can't.

            -- Chip Salzenberg, Free-Floating Agent of Chaos