in reply to Re: Re: Re: Re: Perl Internals - references and symbol table
in thread Perl Internals - references and symbol table

Thanks Elian. The bare blocks have been stumping me. One of the reasons I've been so interested (and why I'm delving into internals) is that I'd like to be able to write subs that are somewhat lexically scoped for iterators and such (Without using anonymous subs, OO etc). I would like to be able to write subs that act like builtins that DWIM. I could start adding ops to the language, but I don't want to even think about writing stuff that I would need to recompile perl on a given target with my own patches.

There are ways of doing what I want with closures and objects easily enough but I am just obsessed with doing it the way I want.

For example ,take a hypothetical sub called elements(\@;$), that non-destructively grabs N elements of off an array lazily.

I'd like to be able to say...
while(my @els = elements(@array, 5) ){ # Do stuff while we have elements... }
I can think of a couple of ways we might be able to have this DWIM.
  1. Install a localized version outside of the caller's scope or otherwise dynamically redefine it for the scope in such a way that it will be restored. (Meaning the first time it is called in a scope, the sub (which is a sub generator) redefines the subname locally and calls the newly installed version. Subsequent calls go straight to the new version until the scope ends and the original sub generator is called next time a scope is entered.
  2. Install a lexical marker in the caller's (xcv_outside?)pad so and use Padwalker to reference our current state. Now we can act lexically, though I dont' think pads are "cleared" so I don't know if this would work in all cases (like if the loop is exited prematurely and there are still elements left to iterate)
  3. Source filters. Ugh. Don't really like them. Feels wrong.


-Lee

"To be civilized is to deny one's nature."

edited: Mon Nov 18 15:34:59 2002 by jeffa - s/<\/ul>/<\/ol>/

Replies are listed 'Best First'.
Re^6: Perl Internals - references and symbol table
by Aristotle (Chancellor) on Nov 18, 2002 at 13:04 UTC
    If I understand correctly, what you really want is to have the iterator tied to the array like with each.
    { my %position; sub elements(\@;$) { my $arr = shift; my $amt = shift || 1; if(not exists $position{$arr} or $position{$arr} < $#$arr) { my ($start, $next) = ($position{$arr}, $position{$arr} += +$amt); return @$arr[$start .. $next - 1]; } else { delete $position{$arr}; return; } } }

    Makeshifts last the longest.

      Along those lines. I don't like the idea of it leaking across scopes. The version I have is a little different. It actually stringifies the reference and caller info to avoid collisions. Using only the ref causes side effects at a distance.
      my @array = (1..12); while(my @els = elements @array, 3 ){ last if grep { $_ eq 2 } @els; } my @five = elements @array 5; # Would get (4,5,6,7,8)!DWIM
      Using both fixes this problem but can still suffer if the iterative construct is exited prematurely.
      { while (my @els = elements @giantarray, 10 ){ # Do stuff last if $els[0] == $somecondition; } redo if $someothercondition; }
      The later probably almost never occur in most code, but when it does, I'm sure it would take much head scratching before deciding where the problem lies.

      -Lee

      "To be civilized is to deny one's nature."
        How about you do as Perl's own each then? It will "leak" the iterator all over the entire program as well - but you can call keys or values to reset it.

        Makeshifts last the longest.

Re: Re:(5): Perl Internals - references and symbol table
by BrowserUk (Patriarch) on Nov 20, 2002 at 05:07 UTC

    I don't suppose this satisfies your criteria? It works, but would screw up if you tried to nest uses of it.

    #! perl -sw use strict; { my $next=0; sub elements(\@$) { my ($ref, $count) = @_; my $max = $#$ref; $next=0, return if $next > $max; my $first = $next; my $last = $next+$count-1; $last = $max if $max < $last; $next += $count; @{$ref}[$first .. $last]; } } my @letters = ('a'..'z'); while(my @els = elements(@letters, 5) ) { print "@els\n"; } __END__ a b c d e f g h i j k l m n o p q r s t u v w x y z

    Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
    Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
    Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
    Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

      What I did in this case was use a hash so there could be multiple instances. The hash key was the stringified args and a join of caller. It almost always works but there are several potential problems.

      If this could be solved generically, then I think you'd be able to implement basic "coroutines" as I understand them. You'd still have to wrap up the start executions in if's or something but it would be a start.

      -Lee

      "To be civilized is to deny one's nature."

        I did play around with some stuff that generated iterator subs on the fly here RFC and debugging tips. That allowed you to use multiple independant iterators. When the handle to the iterator goes out of scope it gets thrown away, bit I think that is getting oo-ish which isn't what your looking for.

        Oh well. I guess I came to the party late and should have read back over the thread before commenting.


        Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
        Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
        Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
        Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.