mauke / Function-Parameters

Function::Parameters - define functions and methods with parameter lists ("subroutine signatures")
https://metacpan.org/pod/Function::Parameters
18 stars 19 forks source link

Should strict include check_argument_types? #41

Closed ccakes closed 1 year ago

ccakes commented 3 years ago

https://github.com/mauke/Function-Parameters/blob/cfb871f898e9a7f3bb3c7c97ec824e6659c62181/lib/Function/Parameters.pm#L268-L271

Should this section here also set check_argument_types? The use case is I'd like to be able to do

use Function::Parameters qw(:lax)

and have Function::Parameters be effectively a no-op. I could send a PR but this might be a breaking change for existing users.

Any thoughts?

mauke commented 1 year ago

"Lax" mode stems from earlier versions of the module, when it would simply rewrite fun foo(PARAMS) { to sub foo { my (PARAMS) = @_;. With the switch to an actual parser (and opcode generator), I added "strict" mode as the more sensible way of doing things, but kept "lax" mode as the backwards-compatible default. Finally, in version 2 of F:P, I switched the default to "strict". In retrospect, I think "lax" mode was perhaps a mistake.

That said, the configuration knobs are still there. If you want to explicitly disable type checks in your code, you can write:

use Function::Parameters {
    fun => { defaults => 'function_lax', check_argument_types => 0 },
    method => { defaults => 'method_lax', check_argument_types => 0 },
};

That's a bit of a mouthful, but you could hide it behind a custom module (whose import just calls Function::Parameters->import with these arguments).

(But I confess I don't really see the point of writing type constraint checks in your code, only to sneakily turn them into no-ops.)

tobyink commented 1 year ago

If you have Type::Tiny 2 or above, you should be able to do something like:

use v5.12;
use Function::Parameters;
use Types::Common 2 -types;

fun add ( ( Int / Any ) $x, ( Int / Any ) $y ) {
    return $x + $y;
}

say add( 1, 1.2 );

Notice that 1.2 isn't an integer, but the code runs and prints "2.2".

This is because Int / Any will evaluate to Any (i.e. no type check) under normal circumstances, but will evaluate to Int when any of the PERL_STRICT, EXTENDED_TESTING, RELEASE_TESTING, or AUTHOR_TESTING environment variables are set to true.

This allows you to have strict type checks during testing, but make them no-ops and run faster in production.

(It would be nice if Function::Parameters could evaluate more complex type constraints without needing the inner parentheses, but so be it.)