in reply to Re: Making each(@ary) work on 5.10?
in thread Making each(@ary) work on 5.10?

Neat! tobyink++

All I need now is something like, say feature::each_on_array, so that the code below:

use feature::each_on_array; @a = (1..1000); while (my ($idx, $item) = each @a) { }

will run on Perl 5.10 and will take no performance hit on 5.12+.

Are you interested in packaging Tie::ArrayAsHash for distribution? There's already Tie::Array::AsHash on CPAN. Perhaps rethink the name because your solution also provides aeach().

package feature::each_on_array; use strict; use warnings; use Tie::ArrayAsHash qw(aeach); sub import { return unless $^V lt 5.16.0; no strict 'refs'; my @caller = caller; *{"$caller[0]::each"} = \&aeach; } 1;

Replies are listed 'Best First'.
Re^3: Making each(@ary) work on 5.10?
by tobyink (Canon) on Jul 27, 2012 at 07:03 UTC

    As I said, there's a reason I called it aeach instead of each. You can define your own sub called each, but if you try to actually use it, you just get the Perl built-in. This goes right down to the Perl tokenizer.

    There are only three ways to call your own each function: qualify your call with the package name (MyPackage::each(@array)), prefix it with an ampersand (&each(\@array) - note that prototype will be ignored, so you need to pass a reference), or call it as a method (but methods can't be called on unblessed arrays, unless you use autobox).

    Now, it is palso ossible to overwrite the core each with your own:

    use Tie::ArrayAsHash 'aeach'; BEGIN { *CORE::GLOBAL::each = \&aeach };

    However, this is a global override rather than being package scoped or lexically scoped. (You might think that it would introduce infinite recursion because aeach internally calls each, but actually it does not. This is because aeach has already been compiled when the override happens, so is not affected by the override.)

    To override each for just a lexical scope is a much harder proposition.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      I don't think you're entirely correct. The code which I posted (feature::each_on_array) works on my 5.10. And I did not override "each" globally, only on the caller's package.

      % perl -I. -Mfeature::each_on_array -E'say $^V; @a = (qw/a b c/); whil +e (($i, $e) = each @a) { say $i, $e }' v5.10.1 0a 1b 2c
      vs
      % perl -I. -Mfeature::each_on_array -E'say $^V; @a = (qw/a b c/); whil +e (($i, $e) = each @a) { say $i, $e } package Foo; @b = (qw/a b c/); +while (($i, $e) = each @b) { say $i, $e }' Type of arg 1 to each must be hash (not array dereference) at -e line +1, near "@b) "

      Perl here does call our subroutine's each.

      I'll be packaging this as a CPAN module; I need this to work on a 5.10 box, and I want to see CPAN Testers result. I'm including Tie::ArrayAsHash for now.

        I stand corrected. Here's the latest version, tested in Perl 5.8.9, 5.10.1 and 5.16.0...

        The import options are these:

        # Import nothing, but use the tied hash interface. use Tie::ArrayAsHash; # Import 'aeach'. use Tie::ArrayAsHash qw(aeach); # Import 'aeach', but call it 'each'. use Tie::ArrayAsHash qw(each); # Import 'aeach' with both names. use Tie::ArrayAsHash qw(-all); # Import 'each' if Perl lt 5.11.0; import 'aeach' regardless. use Tie::ArrayAsHash qw(-auto); # Import 'aeach' renamed it to whatever you like. use Tie::ArrayAsHash aeach => { -as => 'p512each' };

        Still needs proper documentation and test suite, and maybe a better name.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      To override each for just a lexical scope is a much harder proposition.

      ex::override maybe?

      { use ex::override 'each' => \&aeach; ... no ex::override 'each'; }

        I did look at ex::override, but each doesn't seem to show up in that grep on toke.c that they suggest, which seemed to suggest that ex::override would not work.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'