develooper Front page | perl.perl5.porters | Postings from February 2022

Re: arity checking (was Re: PSC #049 2022-01-07)

Thread Previous | Thread Next
From:
Paul "LeoNerd" Evans
Date:
February 14, 2022 17:12
Subject:
Re: arity checking (was Re: PSC #049 2022-01-07)
Message ID:
20220214171233.4d146fef@shy.leonerd.org.uk
I've just encountered another fine use-case for wanting to know the
min/max arity count of a sub before calling it.

I'm writing an nroff parser... I'll spare you the full details but in
brief I have a plaintext input that consists of a short two-letter
"directive" code, followed by some positional arguments:

  .TH NAME 3 "date here"
  .SH HEADING
  .SS Subheading

etc...

My code to parse/dispatch these basically takes the two-letter
directive code and the args in an array, and does:

  my $method = $self->can( "handle_directive_$d" ) or
    $self->die( "Unrecognised directive .$d" );
  return $self->$method( @args );

I can then go off and implement

  sub handle_directive_TH {
    my $self = shift;
    my ( $title, $section, $date ) = @_;
    ...
  }

  # and so on for handle_directive_SH, handle_directive_SS and many
  # many others

Without sub signatures I get no min/max arity checking of these things.
I could hack that in manually via some lookup table or whatever, but
it'd be great if I can just use the sub signatures themselves:

  # date is optional
  sub handle_directive_TH ( $self, $title, $section, $date = undef )
  {
    ...

Problem is if I do that, any arity failures appear to come from
*perl* land in the dispatch logic in the toplevel. My process dies with

  Too few arguments for subroutine 'main::handle_directive_TH' at
  Some/Perl/File.pm line 1234.

That's not very friendly to my end-users. I want them to see a failure
as generated by my parser logic; something like:

  Too few arguments for .TH directive on line 1 at:
  .TH TITLE
           ^

If perl provided me a way to query the min/max arity of a coderef
without invoking it, well this is easy enough to write:

  my $method = $self->can( "handle_directive_$d" ) or
    $self->die( "Unrecognised directive .$d" );

  my ( $minargs, $maxargs ) = builtin::sub_arity $method;
  $self->die( "Too few arguments for .$d directive" )  if 1+@args < $minargs;
  $self->die( "Too many arguments for .$d directive" ) if 1+@args > $minargs;

  return $self->$method( @args );

Perl currently does not provide this. So I can't.

-- 
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About