Folks have already pointed out the weirdness result of mixing my and if in the same statement, but I wanted to point out another stylistic issue. You define $func as a subroutine reference whether it's provided by the user or defined by wannabe_foreach, but you've got it going in two distinct places. Why not mush them together so folks can easily see what $func's ultimate fate is?
use warnings;
use strict;
# A 'wannabe' foreach, which:
# - takes a CODE ref as an optional first argument
# - applies it to the rest of the args
# - If no CODE ref was passed, then it uses a closure of its
# own that simply shoves all the args into an accumulator list
# which it just dumps to STDERR
sub wannabe_foreach {
my ($func, @list, @accumulator);
# Use provided code-ref if there is one,
# otherwise create a simple subref to push onto @accumulator
if ( ref $_[0] eq 'CODE' ) {
$func = shift; # optional code-ref
}
else {
$func = sub { push @accumulator, shift };
}
# If you absolutely gotta be terse there's always
# $func = ( ref $_[0] eq 'CODE' )
# ? shift
# : sub { push @accumulator, shift }
# ;
@list = @_;
$func->($_) for @list;
warn join ",", @accumulator if @accumulator;
}
wannabe_foreach(1..3); # Works. Warns: '1,2,3 at foo.pl line ...'
wannabe_foreach(1..4); # No funkiness here