Thanks for this. The interesting thing is that if I stringify the code to avoid the sub call then I can replicate the ordering from my original post.
I added a false value to get a sense of the cost of the increment operation. value_true is value from your version, and is obviously faster as it does less work.
use warnings;
use strict;
use Benchmark qw{ cmpthese };
my %h;
@h{1001 .. 2000} = (1) x 1000;
my ($e, $vt, $vf) = (0) x 3;
$h{1002} = 0;
cmpthese(-2, {
exist => sub { for (0..999_999) { ++$e if exists $h{1001} } },
exist_str => 'for (0..999_999) { ++$e if exists $h{1001} }',
value_true => sub { for (0..999_999) { ++$vt if $h{1001} } },
value_str => 'for (0..999_999) { ++$vt if $h{1001} }',
value_false => sub { for (0..999_999) { ++$vf if $h{1002} } },
});
__DATA__
Rate exist value_true exist_str value_str val
+ue_false
exist 16.1/s -- -9% -23% -26%
+ -27%
value_true 17.7/s 10% -- -15% -18%
+ -20%
exist_str 20.9/s 29% 18% -- -4%
+ -6%
value_str 21.7/s 34% 22% 4% --
+ -2%
value_false 22.1/s 37% 25% 6% 2%
+ --