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

Hi,

If foo() is documented as:
$ret = foo($sclar, [$arrayref], [$hashref]);
then we know that the second and third arguments are optional, and that some default behaviour will be initiated if they are omitted.

Suppose also that you decide to accept the default behaviour re the second arg, providing only a first and third arg ... does the above piece of documentation tell you how to do that ? Do you expect that you will code it as:
1) $ret = foo($scalar, $hashref); or
2) $ret = foo($scalar, undef, $hashref); or
3) $ret = foo($scalar, '', $hashref);
or do you expect that you will have to consult the documentation for further instruction ? Is there a standard for this type of notation ?

Also, if foo() is instead documented as:
$ret = foo($scalar, [$arrayref, [$hashref]]);
that would presumably dictate that if you wish to provide the third argument, then you must also specify a second argument ... right ? Or is this type of notation too loose for drawing any conclusions at all ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: Docs notation
by Corion (Patriarch) on Jul 27, 2007 at 13:50 UTC

    Perl does not have positional empty parameters:

    foo('bar', , 'baz')

    is exactly the same to Perl as

    foo('bar', 'baz')

    and that's why I definitively tend towards the last documentation:

    $ret = foo($scalar, [$arrayref, [$hashref]]);

    If you have behaviour that can determine whether the second parameter was left out, as in your example by the type of reference passed in, just document that in the prose:

    If the second parameter is a hash reference and no third parameter is passed in, it is interpreted as the third parameter and the second parameter defaults to [...]

    Of course if there is no "natural" order of parameters, consider passing named parameters as a hash:

    # The naming is obviously somewhat abstract here foo( scalar => $scalar, hashref => {...}, things => \@things );

    This has the advantage that you can add new options/parameters later without worrying about the existing code.

Re: Docs notation
by jhourcle (Prior) on Jul 27, 2007 at 14:20 UTC

    In the first case, I'd assume option #1. I know it's possible to code:

    sub foo { my $scalar = shift; my ( $arrayref, $hashref ); if ( UNIVERSAL::isa( $_[0], 'ARRAY' ) { $arrayref = shift; } if ( UNIVERSAL::isa( $_[0], 'HASH' ) { $hashref = shift; } .... }

    Of course, just because it _can_ be coded that way, doesn't mean it actually is. In your second question, I'd agree with the assumption that pashing a hashref requires also passing a second argument.

    ...

    I'm guessing you're intentionally being vague, so that we can see the issues with documentation, but sometimes there is some other context in the documentation ... if you know that there's no reason to pass both an arrayref and a hashref, you could specify:

    $ret = foo($scalar, [$arrayref | $hashref] );

    ...

    But in this case, I'm more interested in knowing if you're asking this question because you're trying to understand some documentation (in which case, what documentation, if it's publicly available?), or if you're asking for advice in writing documentation.

      I saw some documentation the other day:
      MouseClick($window [,$parent] [,$x_offset] [,$y_offset] [,$button] [,$ +delay])
      A few lines further down there were some examples of usage provided, which showed that if you wanted to specify (eg) $delay, but wanted the default value for the other optional args then you had to:
      MouseClick($window, undef, undef, undef, undef, $delay)
      To me, that meant the usage should have been presented as something like:
      MouseClick($window [,$parent [,$x_offset [,$y_offset [,$button [,$dela +y]]]]])
      Not that it matters greatly in this particular instance (as the author had provided examples of usage that clearly demonstrated what was required), but I have some documentation (that needs fixing up) wrt a function that has optional args. And before I fix it up I wanted to get some sort of idea of what that notation actually meant to people - because the more I thought about it, the less certain I became.

      I think the main message I draw from these replies is "Be explicit".

      Thanks guys.

      Cheers,
      Rob
Re: Docs notation
by radiantmatrix (Parson) on Jul 27, 2007 at 14:44 UTC

    It's likely to be #2, since:

    $ret = foo($scalar);

    Is (generally) equivalent to:

    $ret = foo($scalar, undef, undef);

    There's another option, though, and it all depends on how the author wrote his/her code:

    $ret = foo($scalar, [], $hash_ref);

    In other words, it may be necessary to use an empty arrayref, though my gut would say using just undef would be more likely correct.

    <radiant.matrix>
    Ramblings and references
    The Code that can be seen is not the true Code
    I haven't found a problem yet that can't be solved by a well-placed trebuchet
Re: Docs notation
by cdarke (Prior) on Jul 27, 2007 at 14:24 UTC
    The notation is (loosely) Backus-Naur Form, or BNF. Many CPAN modules appear to support the default argument form of undef, but unfortunately not all authors understand the distinction between the examples you gave.
    Some support a kind-of named parameter, which is just a hack into a hash.

    update: On second thoughts, it is probably more likely to be Extended Backus-Naur Form (EBNF).
Re: Docs notation
by doom (Deacon) on Jul 29, 2007 at 20:01 UTC
    As written your first example is ambiguous, because it could be you were trying to indicate that the second and third arguments are anonymous array references.

    My question would be: does anyone really use these BNF syntax diagrams? They seem to be provided at the top of unix man pages primarily for the purpose of confusing newbies.

    What you really need to do is provide examples of the way you expect the code to be used, combined with a written description of each of the arguments, indicating whether they're optional and so on. Demoing the use of "undef" as a placeholder is a good idea: that idiom is not at all obvious to beginners.

    (By the way, it's probably bad form to have more than three or so positional arguments. If at all possible, I would suggest redesigning to use "named options", i.e. an optional hash reference of options in the last place.)

Re: Docs notation
by Anonymous Monk on Jul 28, 2007 at 05:18 UTC
    =head1 FUNCTIONS =head2 C<$ret = foo($scalar, [$arrayref, [$hashref]]);> Takes one to three arguments, the 2nd and 3rd being optional, ex foo($scalar, undef, \%bong ) returns blah blah ... =cut