RFC: new API for Type::Params

Firstly, I'm not planning on breaking compatibility with Type::Params. The new API would live under a different namespace, such as Type::Params2.

The API for Type::Params is currently:

use feature 'state';
use Type::Params qw( compile compile_named_oo );
use Types::Standard -types;

sub function_with_positional_parameters {
  state $check = compile( ArrayRef, Int, Int );
  my ( $list, $start, $end ) = $check->( @_ );

  my @slice = @{$list}[ $start .. $end ];
  return \@slice;
}

sub function_with_named_parameters {
  state $check = compile_named_oo( list => ArrayRef, start => Int, end => Int );
  my ( $arg ) = $check->( @_ );

  my @slice = @{$arg->list}[ $arg->start .. $arg->end ];
  return \@slice;
}

Alternatively, there's:

use Type::Params qw( wrap_subs compile_named_oo );
use Types::Standard -types;

wrap_subs function_with_positional_parameters => [ ArrayRef, Int, Int ];

sub function_with_positional_parameters {
  my ( $list, $start, $end ) = @_;

  my @slice = @{$list}[ $start .. $end ];
  return \@slice;
}

wrap_subs function_with_named_parameters =>
  compile_named_oo( list => ArrayRef, start => Int, end => Int );

sub function_with_named_parameters {
  my ( $arg ) = @_;

  my @slice = @{$arg->list}[ $arg->start .. $arg->end ];
  return \@slice;
}

My suggested API is:

use feature 'state';
use Type::Params2;
use Types::Standard -types;

sub function_with_positional_parameters {
  state $check = signature(
    pos => [ ArrayRef, Int, Int ],
  );
  my ( $list, $start, $end ) = $check->( @_ );

  my @slice = @{$list}[ $start .. $end ];
  return \@slice;
}

sub function_with_named_parameters {
  state $check = signature(
    named => [ list => ArrayRef, start => Int, end => Int ],
  );
  my ( $arg ) = $check->( @_ );

  my @slice = @{$arg->list}[ $arg->start .. $arg->end ];
  return \@slice;
}

It would also support the inside-out technique:

use Type::Params2;
use Types::Standard -types;

signature_for function_with_positional_parameters => (
  pos => [ ArrayRef, Int, Int ],
);

sub function_with_positional_parameters {
  my ( $list, $start, $end ) = @_;

  my @slice = @{$list}[ $start .. $end ];
  return \@slice;
}

signature_for function_with_named_parameters => (
  named => [ list => ArrayRef, start => Int, end => Int ],
);

sub function_with_named_parameters {
  my ( $arg ) = @_;

  my @slice = @{$arg->list}[ $arg->start .. $arg->end ];
  return \@slice;
}

There would be a shortcut for methods:

signature_for method_with_named_parameters => (
  method => 1,
  named  => [ list => ArrayRef, start => Int, end => Int ],
);

sub method_with_named_parameters {
  my ( $self, $arg ) = @_;

  my @slice = @{$arg->list}[ $arg->start .. $arg->end ];
  return \@slice;
}

Comments? Do people think this would be an improvement?

7 Comments

TIL Type::Params :-)

Not having any practical experience with it and referring to just the examples, I feel the second syntax is much cleaner. Certainly, getting rid of compile_named_oo is a win.

However, I don't think the Perl world needs YetAnotherNumberedModule. Couldn't you just add signature and signature_for to the current module and let the user do:

use Type::Params qw/signature signature_for/;

If you don't want the user to have to use an explicit import, maybe Type::Signature would be a good name. Or even Type::ParamsSignature. Anything but Type::Params2.

Wouldn’t it be close enough to update the documentation to prominently describe only the new style, and for the old interface just put some stubs near the end of the POD that merely say stuff like (e.g.) this?

compile_named_oo(...): does the same thing as signature(named=>[...])

--modern. I could live with that.

I agree. At the top you can put a blurb like:

Note: This module was given a "facelift" in 2022 with a more natural API. These docs have been revamped to feature the new API prominently, but the old API's functions are still documented within, mapped to the new calls.

I really dislike marketing/judgy terms like “modern” for this kind of thing. “Modern” conveys nothing about the interface, it’s just what someone thinks of it – or rather, thought of it at the time the term was assigned. Next time the API gets a facelift, what then? Postmodern? Hypermodern? What do you put in the documentation, “-modern is actually deprecated now”? Or do you – and perish the thought – break backcompat?

It’s rather better to use descriptive terms that highlight some defining characteristic of the interface. In this particular case, I’d suggest maybe -signatures. That isn’t likely to be invalidated by the next facelift.

Expressing an opinion is not per se a problem, but it’s the documentation to which that function belongs, not the interfaces.

Leave a comment

About Toby Inkster

user-pic I'm tobyink on CPAN, IRC and PerlMonks.