in reply to Re: Getting for() to accept a tied array in one statement
in thread Getting for() to accept a tied array in one statement

for (tie @ary, "My::Class", "some", "contents") { ... } # NOPE

does not work because for() gets a single-element list which is the tied object, not the tied array itself.

for (do { tie @ary, "My::Class", "some", "contents"; @ary }) { ... } #NOPE

does not work because for() gets an ordinary (non-magical) list of values. All the values from the tied array have been FETCH-ed. I need to iterate over the tied array so code inside the loop block and FETCH are executed once for each element, together.

tie @ary, "My::Class", "some", "contents"; for (@ary) { ... }

works, but I want something more similar to:

for (wrapper(@ary)) { ... }

where @ary is an ordinary array or a list of values.

Replies are listed 'Best First'.
Re^3: Getting for() to accept a tied array in one statement
by choroba (Cardinal) on Apr 16, 2019 at 13:31 UTC
    > because for() gets an ordinary (non-magical) list of values.

    That's not how I understand the output. It seems FETCHSIZE is only called once, but each element is fetched right before the iteration:

    #! /usr/bin/perl use warnings; use strict; use feature qw{ say }; { package My; use Tie::Array; use parent -norequire => 'Tie::StdArray'; sub TIEARRAY { warn "TIE: @_\n"; my $class = shift; bless [@_], $class } sub FETCHSIZE { warn "SIZE: @_\n"; return scalar @{ $_[0] } } sub FETCH { warn "FETCH: @_\n"; my ($ar, $idx) = @_; my $e = $ar->[$idx]; return ++$e } } for my $e (do { tie my @ar, 'My', qw( a b c ); @ar } ) { say "MAIN: $e"; }
    Output:
    TIE: My a b c SIZE: My=ARRAY(0x21eff40) FETCH: My=ARRAY(0x21eff40) 0 MAIN: b FETCH: My=ARRAY(0x21eff40) 1 MAIN: c FETCH: My=ARRAY(0x21eff40) 2 MAIN: d

    for my $e (@ar), on the other hand, calls FETCHSIZE before each FETCH.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      It seems FETCHSIZE is only called once, but each element is fetched right before the iteration:

      That's correct. for (@a) iterates over the indexes as if you had done for (0..$#a). This differs from for ((), @a), which retrieves the contents of @a up front.

      Yup, I was referring to for(), where an additional FETCHSIZE is invoked for each iteration, which is useful in the case where we want to size to be dynamic/growing.

Re^3: Getting for() to accept a tied array in one statement
by Veltro (Hermit) on Apr 16, 2019 at 13:47 UTC

    This:

    for (tie @ary, "My::Class", "some", "contents";) { ... }

    is exactly what you should NOT be doing

    Read: Tying-Arrays: If someone outside the class tries to dereference the object returned (doubtless thinking it an ARRAY ref), they'll blow up. This just goes to show you that you should respect an object's privacy.

    FETCH and FETCHSIZE are exactly for that you can: 'respect an object's privacy':

    Something like this:

    my $aryt = tie @ary, "My::Class", "some", "contents"; @ary = ... ; for (0..($aryt->FETCHSIZE-1)) { do-something($aryt->FETCH($_)); }

      But isn't the whole point of tie that one can use the tied array as if it were a normal array and all the magic happens without ever calling the classes' methods explicitly?

        Yes, my point is that you simply can't assume an object can be de-referenced to an array. The tie mechanism useful for creating algorithms that can handle objects without implying knowledge about their implementation. Otherwise this would defeat the whole purpose using tie. So it is still a good question, any other solutions appreciated.

Re^3: Getting for() to accept a tied array in one statement
by LanX (Saint) on Apr 16, 2019 at 16:00 UTC
    you can't bend for into an object's method.

    Perl != Python

    the closest to a drop in replacement is maybe a customfunction sub xfor (&&) :

    xfor {@arr} sub { ...};

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      Didn't hdb just do that? :-)
        and from which Perl version on? :-)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice