Subject: | In `around _generate_coerce` the $value may be a string of Perl code with side-effects |
_generate_coerce gets passed $value which will be a string of Perl code usually along the lines of:
&$default_for_foo($_[0])
Evaluating the string (which in this case will call the coderef) may have side-effects, such as incrementing a counter.
my $object_id;
has id => (is => 'lazy', isa => Int, default => sub { ++$object_id });
MooX::TypeTiny passes this string on to Type::Coercion like:
$coercion->inline_coercion($value)
And this results in inline code like the following being generated:
$new_value = passes_type_check( &$default_for_foo($_[0]) )
? &$default_for_foo($_[0])
: process_the_value( &$default_for_foo($_[0]) )
So $default_for_foo gets called twice, which is a problem if it has side-effects, and potentially inefficient even if it does not.
The documentation for `inline_coercion` is:
"inline_coercion($varname)"
Much like "inline_coerce" from Type::Tiny.
This has a typo, because it means "inline_check" from Type::Tiny. Although it isn't explicitly stated what $varname is expected to be, the examples just show a Perl scalar variable name as a string. In practice, indexing into arrays and hashes, including references, to arbitrary depths should always be fine too.
Type::Tiny and Type::Coercion never actually check whether $varname is sane; they just assume you know what you're doing. The strings passed by MooX::TypeTiny mostly work, but they cause strange behaviour in certain edge cases.
Suggested solution would be instead of:
$coercion->inline_coercion($value)
Do this:
sprintf('do{my $tmp=%s;%s}', $value, $coercion->inline_coercion('$tmp'))