On Fri, Jan 21, 2022 at 06:29:27PM +0100, demerphq wrote: > So consider, I own a framework whose api is that I accept a callback from > the caller. I tell the caller that my api will call his sub with 1 > argument, lets say "key". There's the crunch. If your framework promises to call always with one arg, then if you call the callback with 2 args, you've broken your promise. If you've promised 1 arg, then the user of your framework should be able to pass either of these subs: sub callback { croak unless @_ == 1; my ($x) = @_ } sub callback ($x) { } If the framework promises it will pass at *least* one arg, then these should both be valid: sub callback { croak unless @_ >= 1; my ($x) = @_ } sub callback ($x, @) { } If the framework says you can't trust it in any fashion, then both of these would do: sub callback { my ($x) = @_ } sub callback ($x=undef, @) { } There is no fundamental difference between each pair of subs. In the first pair, the writer of the sub has made a conscious choice to write a subroutine with strict arity checking, both signatured and unsignatured variants. Now you can of course argue that signatures make it *easier* to inadvertently write subroutines which have arity checking when with hindsight it would have been easier to migrate to a new version of the framework if you had disabled arity checking. But its not a fundamental design problem with signatures. If a framework author wants to break a promise about arity, they could always call it with an eval: if (defined $extra) { eval { $self->$callback($x, $y, $extra) }; goto fallback if $@ =~ /Too many arguments/; } else { fallback: $self->$callback($x, $y); } which is as much (or little) hacky as introspecting the callback to see if its a sub with a declared arity range. -- You're only as old as you look.Thread Previous | Thread Next