LanX has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I was experimenting with an enumerator function to iterate thru values and indices at the same time.

while this works (>5.10)

sub enum (\@$$){ ... } use feature 'state'; while ( enum @a => state $value, state $i ){ print "enum: $i $value\n"; }

it's not possible to write

   while ( enum @a => state( $value, $i ) ){

without getting "a not enough arguments" error.

It's the same for my and our ...

So for what I can see this call tst(my($x,$y))

DB<7> sub tst ($;$) {print scalar @_ } DB<8> tst(my($x,$y)) 1

gets only one parameters passed! (UPDATED example)

So avoiding the syntax error by changing the prototype to make the third one optional - i.e.enum (\@$;$) {} - doesn't help.

That's a parsing error, or do I miss a special reason to handle it this way?

Cheers Rolf

UPDATE: OK I got it, my ($a,$b) seems to be handled like a shorthand for my ($a,$b)=(undef,undef) and therefore just the scalar value of a list assignment is returned.

In other words my returns the number of declared variables...

DB<3> sub tst {print scalar @_ }<P> DB<4> tst( my ($a,$b)) 2 DB<5> tst( my ($a,$b,$c)) 3 DB<6> tst( my ($a,$b,$c,$d)) 4

Replies are listed 'Best First'.
Re: why doesn't "my ($a,$b)" return a list?
by moritz (Cardinal) on Aug 19, 2010 at 14:39 UTC
    Prototypes are not function parameters; rather they alter parsing.

    Which is why it doesn't matter what an expression returns - it only matters how its parsed. For example a sub that returns a list doesn't work either in your example:

    $ perl -we 'sub list { 1, 2}; sub enum(\@$$) { }; enum my @a, list()' Not enough arguments for main::enum at -e line 1, at EOF Execution of -e aborted due to compilation errors.

    Perl sees the comma operator as returning a list in this context, while it assumes that a a variable declarator returns an item.

    Perl 6 - links to (nearly) everything that is Perl 6.
      My point was that my, our and state aren't subs but operators and shouldn't be handled as subs.

      The problem stays even without prototypes.

      Anyway I think I found the answer, my returns the number of initialized variables, see the update in the OP.

      Cheers Rolf

        The problem stays even without prototypes.

        Really? With a better prototype:

        $ perl -wE 'sub list { 1, 2}; sub enum(\@@) { @_[1,2] = (1, 2)}; enum +my @a, state ($x, $y); say $x, $y' 12

        Or with no prototype:

        $ perl -wE 'sub list { 1, 2}; sub enum { @_[0,1] = (1, 2)}; enum my @a +, state ($x, $y); say $x, $y' 12

        To me this looks like the scalar context from the prototype was the problem - our maybe you meant a different problem? If so, care to elaborate?

        Perl 6 - links to (nearly) everything that is Perl 6.

        My point was that my, our and state aren't subs but operators and shouldn't be handled as subs.

        The named operators (my, print, substr, time, etc) are just like subs in many regards, to the point of being called (builtin) functions.

        my happens to have a compile-time effect, but it still behaves like a sub at run-time.

Re: why doesn't "my ($a,$b)" return a list?
by ikegami (Patriarch) on Aug 19, 2010 at 14:47 UTC

    Prototype "$" imposes a scalar context on the corresponding expression in the parameter list. That means that my cannot possibly return a list. Without trying, I'd guess it returns the last of the values it would normally return. To avoid this problem, remove the prototype or use

    tst(my $x, my $y);

    (Spotty internet delayed my posting. Sorry for repeating what moritz covered.)

      > Without trying, I'd guess it returns the last of the values it would normally return.

      nope my returns the number of declared variables, see the update in the OP.

      > To avoid this problem, remove the prototype

      prototype is not the problem.

      > or use use

      > tst(my $x, my $y);

      which unfortunately results in tst(state $x, state $y); in my case!

      Cheers Rolf

        nope my returns the number of declared variables, see the update in the OP.

        Sorry, but you are mistaken.

        $ perl -wE'say(scalar(my ($x, $y)))' Use of uninitialized value $y in say at -e line 1.

        It doesn't return the count. Like the error message shows, it returns the last element it would have returned (as I had guessed).

        which unfortunately results in tst(state $x, state $y); in my case!

        Or

        &tst(state ($x, $y));

        But I prefer what you had over using "&".

Re: why doesn't "my ($a,$b)" return a list?
by ikegami (Patriarch) on Aug 19, 2010 at 14:50 UTC

    my ($a,$b) seems to be handled like a shorthand for my ($a,$b)=(undef,undef)

    What my() returns in scalar context (the last value it would normally return in list context) is unrelated to what list assignment returns in scalar context (the count of items returned by its RHS).

    >perl -wE"$r = \my ($x,$y,$z); $$r = '!'; say $x; say $y; say $z" Use of uninitialized value $x in say at -e line 1. Use of uninitialized value $y in say at -e line 1. ! >perl -wE"my $c = my ($x, $y, $z) = (undef, undef); say $c" 2
      no idea what you are talking about, I'm getting exactly the same results in list context like with an implicit assignment of undefs.

      Using deref-operator \ is another case .

      DB<7> sub tst2 {print scalar @_ } DB<8> tst2( my ($a,$b,$c,$d)) 4 DB<10> tst2( my ($a,$b,$c)) 3 DB<11> tst2( my ($a,$b)) 2 DB<12> tst2( my ($a)) 1 DB<13> tst2( my ($a,$b,$c,$d)=(undef,undef,undef,undef)) 4
      UPDATE: ah sorry never mind!

      Cheers Rolf

Re: why doesn't "my ($a,$b)" return a list?
by kejohm (Hermit) on Aug 20, 2010 at 12:17 UTC

    On a side note, as of v5.12, the each(), keys(), and values() functions now operate on arrays, which might be what you are looking for. Here is an example:

    #!perl use strict; use warnings; use feature qw(:5.12); my @array = 'a' .. 'g'; while( my( $index, $value ) = each @array ) { say "$index -> $value"; } __END__ 0 -> a 1 -> b 2 -> c 3 -> d 4 -> e 5 -> f 6 -> g
      Yes indeed!!!

      Excellent, thx for showing :)

      (I was already wondering why it's not implemented this way)

      BUT just recently I got bitten by trying to nest two while (each ) on the same hash, because the iteration-pointer is tied to the hash... :(

      Cheers Rolf

        just recently I got bitten by trying to nest two while (each ) on the same hash, because the iteration-pointer is tied to the hash
        If you do not change the hash in the loop, you can use your own iterator like that:
        sub hash_iterator { my %h = @_; return sub { each %h; } } # make_iterator my %test = (k1 => 'v1', k2 => 'v2', k3 => 'v3', 'k-last' => 'v-last'); my $it1 = hash_iterator(%test); my $it2 = hash_iterator(%test); while(<>){ print join ':',($it1->())[0,1]; print ';',join ':',($it2->())[0,1]; print ' - ',join ':',($it2->())[0,1]; print "\n"; }
      > keys(), and values() functions now operate on arrays,

      are you sure? I was only able to find each in perldelta ...

      can't test it myself!

      Cheers Rolf

        Yes, it is mentioned in the perlfunc manpage under keys and values. Strange that is not in perldelta.

        Update: Link fixed.