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

Many (some? Me anyway, but a long time ago:) have been bitten by trying

my $aryref = \qw(A B C);

to generate a ref to an array of quoted scalars, and ended up with a a ref to the last quoted scalar. This is explained in perlref

Taking a reference to an enumerated list is not the same as using square brackets--instead it's the same as creating a list of references!
@list = (\$a, \@b, \%c); @list = \($a, @b, %c); # same thing!

Now, for reasons of my own, I wanted to generate an array of references to scalar, but the twist is that the scalars in question are a list of sequential integers.

Now the easy way to generate a list of sequential integers is the range operator 3 .. 5,

so I tried [ \(3 .. 5)]

and got [[3,4,5]]

Which was not what I expected. It's easy enough to work around

[ map \$_, 3 .. 5 ]

or even a golfish

 [\(@_=(3..5))],

but it seems strange that the first option doesn't do what I thought. Is this a bug, special magic, what everyone else expected?


Examine what is said, not who speaks.

The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Replies are listed 'Best First'.
Re: Anon. array of refs to a range generated list of scalars.
by jdporter (Paladin) on Jan 18, 2003 at 17:11 UTC
    I do think it's strange that perl is genning up an array where you didn't ask for one. Maybe it's a bug.

    But besides your map solution, this also works:
    \( (sub{6..9})->() )
    Note that using the ampersand form to call the sub doesn't work. I guess perl decides that you want a ref to the sub if you do that.
    (Update; thanks Aristotle.) You could also write that as
    \( &{sub{6..9}}() )

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.

      \do{6..9}
      -sauoq
      "My two cents aren't worth a dime.";
      

        Neat! From that I realised that you can also do

        [\map$_,1..9]
        But yours is much tidier.

        Examine what is said, not who speaks.

        The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      Does too, you have to write \( &{sub{6..9}}() )

      Makeshifts last the longest.

(jeffa) Re: Anon. array of refs to a range generated list of scalars.
by jeffa (Bishop) on Jan 18, 2003 at 18:12 UTC
    Interesting stuff ... i don't have an answer, but i did notice something peculiar:
    use Data::Dumper; print Dumper [(3,4,5,6)]; print Dumper [(3 .. 6)]; print Dumper [\(3,4,5,6)]; print Dumper [\(3 .. 6)];
    The first two prints yield the same results as expected, but the second two yield different results:
    [\(3,4,5,6)] yields $VAR1 = [\3,\4,\5,\6];
    [\(3  .. 6)] yields $VAR1 = [[3,4,5,6]];
    
    If i had to take a guess, i would say that the range operator is yielding some scwoowey wesults ...

    jeffa

    shhhh ... be vewy vewy quiet ... i'm hunting bugs ...
Re: Anon. array of refs to a range generated list of scalars.
by pg (Canon) on Jan 18, 2003 at 18:28 UTC
    I think this is a "bug", but not necessary to be a bug introduced during the implementation phase. This most likely is a bug introduced at the spec phase, or it is something never clearly defined. (At the end of this post, I have another exapmple)

    One of the benefit we get from Perl is that it has very "rich" syntax, many shortcuts... However this may come back and bite us, or to be more precise bite Perl, not really us.

    The richness of Perl's syntax actually sacrifices the rightness of its syntax to a certain level.

    Thanks for BrowserUK, I tried this piece of code, base on his thought:
    use Data::Dumper; { $a = 1; $b = 2; $c = 3; @a = \($a,$b, $c); print @a, "\n";#this is an array of ref } { $a = 1; $b = 2; $c = 3; $d = [\($a,$b, $c)]; print @$d, "\n";#this is an array of ref } { @a = \(1..3); print Dumper(@a);#this is an ref to an array }
    This does not make sense to me at all. One may come up with some explanation for this, but I would not buy any explanation.

    My philosophy is simple:
    1. Good syntax should be consistant all the way
    2. What I actually get matches what I see
    Another example of bad syntax: the other day I tried redo within a do {} until block, but Perl complains that I could not use redo outside a loop block, which means Perl does not take do {} until as a loop block.

    Thanks for gjb, he explained to me that he experienced the same problem a while back, and he figured out that is what Perl does, and it does not take do {} until as a loop block.

    So it is not a bug, it is a feature, from the view of Perl's implementation phase, but this syntax is definitely flawed. It does not make any sense that, a do {} until block is not a loop block, when I am clearly using it for ITERATING.

    Update

    This is a very high-yielding discussion, and I must say I learned lots, thanks fellows.

    However my point still stands. My point is regardless what is making the iteration, regardless what is being iterated, regardless whether the iteration is IMPLICIT or explicit, Perl actually knows there is a BLOCK it should iterate through, and in fact it is doing that iteration for us, then redo is within a loop block (or to be precise, a loop block Perl refused to recognize, although obviously it recognized and LOOP's thru), so redo should be handle as usual.

    This is what I expected to happen, ;-) I still think it is what should happen.
      Another example of bad syntax: the other day I tried redo within a do {} until block, but Perl complains that I could not use redo outside a loop block, which means Perl does not take do {} until as a loop block.
      That is documented behaviour (see perlsyn), though I must agree not very consistent. It applies not only to do {} until but also to do {} while. perlsyn suggests a workaround like this
      do {{ next if /^#/; # do something }} until /^\s*$/;
      but you have to adjust this to be able to use last.

      My suggestion is to not use those constructs altogether and instead emulate them with bare blocks and redo ...

      # do {} while condition { # some code redo if condition; } # do {} until condition { # some code redo unless condition; }

      -- Hofmator

        Argh. Please don't use naked blocks with redo as loops, it's a nightmare to read. When I see a naked block, I expect to be looking at a private lexical scope, not an unadorned loop. If you need next, wrap the inner part with a naked block:
        do {{ $bar; baz() or next; }} while $foo;
        If you need last, wrap the whole thing:
        { do { $bar; baz() and last; } while $foo; }
        Of course, if you need both, it does get awfully clumsy:
        LOOP: { do {{ $bar; baz() or next; quux() and last LOOP; }} while $foo; }
        In that case, and if you're so inclined then maybe in the other cases as well, I propose:
        while(1) { $bar; baz() or next; quux() and last; }
        At least it documents the loop nature of the block, even if the break condition is again somewhat hidden.

        Makeshifts last the longest.

      I think the thing with the do {} syntax is that you aren't iterating with the do block.

      You are iterating the do block itself.

      For example:

      $i=5; print do{ --$1 }; # prints 4 $i=5; print do{ --$i } while $i; # prints 43210

      However, this is directly analogous to

      $i=5; print --$1; # prints 4 $i=5; print --$i while $i; # prints 43210

      In the latter example, its very clear that the while modifier form is iterating the print.

      The former example, the while modifier is iterating the print also. It just so happens that the print has a do block as one of its terms. This is made clearer if you use the brackets on the print function like this.

      $i=5; print( do{--$i;} ) while $i;

      The confusion comes because we often format the construct like this

      $i=5; do { print --$i; } while ($i);

      Which makes it look like an iterate-at-least-once version of

      $i = 5; while ($i) { print --$i; }

      But you can show the difference by doing

      my ($i, $j) = (5, 0); $j += do { print --$i; } while ($i); print $j; # prints 5.

      Where the value 5 comes from the accumulation of the five 'successful' (1) return codes from the print function.

      Additionally

      If there is an inconsistancy with do, it's that the way it operates as an rvalue, makes it look somewhat analogous to the sort, map & grep functions, in as much as I half expected

      print do( 'fred' ); to work like print do{ 'fred' } Somewhat like

       print map $_, 'fred'; is similar to print map{ $_ } 'fred';.

      Actually, the error message from

       print do( 'fred' ); confuses me completly.


      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

        Actually, the error message from print do( 'fred' ); confuses me completly.
        What error message? You are aware of the different variants of do? From perldoc -f do
        do BLOCK [...] do SUBROUTINE(LIST) [...] do EXPR Uses the value of EXPR as a filename and executes the contents of the file as a Perl script.
        so probably the file named 'fred' doesn't exist and do returns simply undef - at least that's what it does here (on perl 5.6.0) generating thus a warning about Use of uninitialized value in print ...

        -- Hofmator

Re: Anon. array of refs to a range generated list of scalars.
by Arien (Pilgrim) on Jan 19, 2003 at 14:47 UTC
    Says the manual about the range operator:
    In list context, it returns an list of values counting (up by ones) from the left value to the right value. If the left value is greater than the right value then it returns the empty array.

    What is that "n" doing there? It seems "list" was once "array"... (update: the documentation for Perl 5.6 indeed says "array", I am quoting from the docs for 5.8) And shouldn't that last part be "the empty list"?

    A couple of sentences later, it says:

    In the current implementation, no temporary array is created when the range operator is used as the expression in foreach loops, but older versions of Perl might burn a lot of memory when you write something like this:
    for (1 .. 1_000_000) { # code }

    This seems to suggest that when not used in for (foreach) a temporary array is created, which would explain a lot...

    — Arien

      This seems to suggest that when not used in for (foreach) a temporary array is created...
      It's not clear. Certainly an array seems to be created in the case of \(5..9), because a reference to the array is returned. (This in itself is very odd.)

      But in the case of @a = (5..9), there's no way to tell (without guts diving).
      And the range operator is overloaded to have completely different semantics in scalar context,
      so we can't even do the simple $n=(5..7); if ( $n == 3 ) test for an array.

      jdporter
      The 6th Rule of Perl Club is -- There is no Rule #6.