in reply to Re: Adding attributes to values?
in thread Adding attributes to values?

Well I am looking at making (yet another) module for adding signatures to Perl subroutines.

I know that there are a lot of solutions to this problem already, but of course none of them works exactly like I want them to. The problem with them is generaly that you have to choose if you want positional argument passing or named argument passing, but a single subroutine cannot have both. I want it to be possible to pass the arguments either as positional arguments or as named arguments. The caller should decide what they want to use.

To make that possible I need some way to distinguish a hash reference that contains named arguments and one that is just a normal argument. By associating an attribute with a hash refernence that might be possible.

And yes I know I will probably not be able to make a module that is better than what already exists on CPAN, but you can't blame a guy for trying :) And I am learning a lot of Perl along the way.

Replies are listed 'Best First'.
Re^3: Adding attributes to values?
by rminner (Chaplain) on Oct 21, 2007 at 10:26 UTC
    Hi,

    you might achieve concurrent use of named and positional args by doing the following:
    If a single hash_ref is passed, then treat it as single hash_ref containing named arguments. Otherwise consider them to be positional.

    For Example:
    sub get_args { if ((scalar(@_) == 1) && ref($_[0]) eq 'HASH') { print "got named args!\n"; } else { print "got positional args\n"; } } sub named_or_positional { get_args(@_); } named_or_positional({foo => 'avalue' , bar => ['a', 'b']}); named_or_positional('whatever' , 'we', 'are', 'passing');

    Only Limitation: you won't be able to use a single hash_ref as a positional argument (as it would be treated like an named arg). The Passing of named arguments as a hash ref is also recommended in "Perl Best Practices" by Damian Conway as it catches named arguments where the number of args is odd and not even(usually caused by some typo). This bears the advantage that you catch those typos at compile time and not at runtime.

      Yes that is one possible solution to the problem and one that is used by one of the modules that are alread on CPAN. It does however have some problems.

      1. Makes it possible that some hard to find bugs are introduced. For instance a function that takes a list of elements and processes them in someway. If that list contains just one item and that item is a hash ref, the item is interpreted as a named argument which is not what is intended. This can give some strange behaviour and the bug can be hard to track down for the module user.
      2. It creates a special case that can be somewhat un-intuitive for people using the module to create subroutine signatures.
        In that case you might simply pass all named args inside a hash_ref and all positional args inside an array reference. Downside of all this is of course an extreme amount of diffrently shaped brackets getting used ...
        sub get_args { if (scalar(@_) == 1) { if (ref($_[0]) eq 'HASH') { return "got named args!\n"; } elsif (ref($_[0]) eq 'ARRAY') { return "got positional args\n"; } else { die "argument wasn't a hash or array reference!\n"; } } else { die "got more than one arg!\n"; } } sub named_or_positional { print get_args(@_); } named_or_positional({foo => 'avalue' , bar => ['a', 'b']}); named_or_positional(['whatever' , 'we', 'are', 'passing']); named_or_positional('whatever' , 'we', 'are', 'passing');

        Then you would have to check whether there is a single hash_ref or a single array_ref for determining whether it's positional or named. Any other case than a single hash or array ref would have to be considered a error.

        If you don't mind the additional overhead of square/curled brackets, then it would allow you simple differentiation of named an positional args.
Re^3: Adding attributes to values?
by GrandFather (Saint) on Oct 22, 2007 at 00:06 UTC

    Personally I'd much rather well documented named parameters with sensible defaults and parameter checking by the called code. Positional parameter passing is simply not attractive unless there is only one (or no) parameter.


    Perl is environmentally friendly - it saves trees

      I think positional parameters are ok if you are not passing more than 3 or 4 and you don't have any dummy parameters. What I consider to be ok also depends on if the function is used often or not. For rarely used functions I find that named arguments can often make the code more self-documenting. For functions that are used often I often prefer the less verbose style of positional parameter passing as long as the criteria above i met.

      But such things are matter of personal coding style. I want to create a module for parameter validation that lets the user of a function with parameter validation decide the appropriate calling style and the module author just worrying about writing the appropriate signature. If the module turns out to be any good I will post it as an RFC under Meditations.