Subject: | Nasty interaction between compile() and $1 |
Date: | Thu, 19 Apr 2018 15:49:11 +0200 |
To: | bug-Type-Tiny [...] rt.cpan.org |
From: | Marc Ballarin <marc.ballarin [...] 1und1.de> |
Hi,
I came across the following, surprising interaction between compile()
with certain types and capture variables. I am slightly surprised, I did
not notice this earlier, since I use Type::Tiny a lot, and for quite
some time.
It seems, that a compiled Int-check destroys the passed in value, after
successfully validating it, if a capture variable was passed in
directly. It works fine, if a temporary variable is used.
The output of the script below is like this:
*** using direct $1
Use of uninitialized value $int in concatenation (.) or string at
type.pl line 11.
after TT Int check: ''
after manual Int check: '123'
after TT Str check: '123'
after assert_valid Int check: '123'
*** using temporary
after TT Int check: '123'
after manual Int check: '123'
after TT Str check: '123'
after assert_valid Int check: '123'
Regards,
Marc
Test script:
#!/usr/bin/perl
use 5.014;
use warnings;
use Type::Params qw(compile);
use Types::Standard qw(Str Int);
sub check_int_tt_compile {
state $check = compile(Int);
my ($int) = $check->(@_);
say "after TT Int check: '$int'";
}
sub check_str_tt {
state $check = compile(Str);
my ($int) = $check->(@_);
say "after TT Str check: '$int'";
}
sub check_int_manual {
my ($int) = @_;
die "no Int!" unless $int =~ /^\d+$/xa;
say "after manual Int check: '$int'";
}
sub check_int_tt_no_compile {
my ($int) = @_;
Int->assert_valid($int);
say "after assert_valid Int check: '$int'";
}
my $string = 'a123';
say '*** using direct $1';
if ($string =~ /a(\d+)/xa) {
check_int_tt_compile($1);
check_int_manual($1);
check_str_tt($1);
check_int_tt_no_compile($1);
}
say '*** using temporary';
if ($string =~ /a(\d+)/xa) {
my $matched = $1;
check_int_tt_compile($matched);
check_int_manual($matched);
check_str_tt($matched);
check_int_tt_no_compile($matched);
}