http://qs1969.pair.com?node_id=1176871


in reply to split problem

G'day rmarkman,

Welcome to the Monastery.

Update (strike): I looked up the error message and made an incorrect inference. I suspect I read "off the end of the string" as "off the end of the array". Anyway, regardless of the reason, what I wrote is wrong and is now stricken.

You're getting the error because you're attempting to assign a value to an element past the end of the array. If you search for "Modification of a read-only value attempted" in "perldiag -- Perl diagnostic messages" you'll get a lot of information about this. However, the opening sentence sums up yor problem:

"You tried, directly or indirectly, to change the value of a constant."

Your split statement, as written, only produces 6 elements: ('A' .. 'F'). You can print $#flds or scalar(@flds) to confirm this.

When you add a LIMIT of -1, you get 10 elements. This behaviour is documented in split: there's examples roughly in the middle of the page.

With the code as posted, both $flds[16] and $flds[8] are undefined. Attempting to assign undef doesn't cause an issue:

$ perl -we 'undef=undef' $

Attempting to assign 0 generates the error you're getting:

$ perl -we 'undef=0' Modification of a read-only value attempted at -e line 1. $

If you use split like this:

@flds = split(/(\t)/, $value);

You'll get 18 elements. That's also documented (at the end of the page).

— Ken

Replies are listed 'Best First'.
Re^2: split problem
by kennethk (Abbot) on Nov 29, 2016 at 23:23 UTC
    Except that if you assign any value past the end of an array, Perl is supposed to automatically lengthen the array to accommodate the value.
    use strict; use 5.10.0; my @flds; $flds[16] = undef; say 0+ @flds;
    I can see no rational reason to treat an array holding the results of a split differently other arrays.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      "Except that if you assign any value past the end of an array, Perl is supposed to automatically lengthen the array to accommodate the value."

      You're correct. See my update. I've stricken the text concerning "past the end of the array".

      — Ken

        Hi, thank you

        I've been trying to reproduce the error and I can do it by marking the array readonly

        $ perl -e " use Data::Lock qw/ dlock /; use Devel::Peek; my @f; + Dump\@f; dlock \@f; Dump\@f; $f[1]=1; "
        SV = IV(0x3f9ad8) at 0x3f9adc
          REFCNT = 1
          FLAGS = (TEMP,ROK)
          RV = 0x99bb0c
          SV = PVAV(0x3fa970) at 0x99bb0c
            REFCNT = 2
            FLAGS = (PADMY)
            ARRAY = 0x0
            FILL = -1
            MAX = -1
            ARYLEN = 0x0
            FLAGS = (REAL)
        SV = IV(0x3f9ad8) at 0x3f9adc
          REFCNT = 1
          FLAGS = (TEMP,ROK)
          RV = 0x99bb0c
          SV = PVAV(0x3fa970) at 0x99bb0c
            REFCNT = 2
            FLAGS = (PADMY,READONLY)
            ARRAY = 0x0
            FILL = -1
            MAX = -1
            ARYLEN = 0x0
            FLAGS = (REAL)
        Modification of a read-only value attempted at -e line 1.

        That split is somehow is marking it readonly is so weird :D

Re^2: split problem
by stevieb (Canon) on Nov 29, 2016 at 23:16 UTC

    There must be something else the issue here, as if you remove all of the trailing tabs from the string, it works fine on all versions of perl I have installed currently.

    Works:

    use warnings; use strict; my $value = "A\tB\tC\tD\tE\tF"; my @flds = split(/\t/, $value); $flds[16] = undef; $flds[8] = 0; print scalar @flds; __END__ 17

    Broken:

    use warnings; use strict; my $value = "A\tB\tC\tD\tE\tF\t\t\t\t\t\t"; my @flds = split(/\t/, $value); $flds[16] = undef; $flds[8] = 0;

      Use Devel::Peek with working/nonworking to see the difference

      Sounds like a bug in perl

      #!/usr/bin/perl -- use strict; use warnings; use Devel::Peek qw/ Dump /; eval { my $value = "A\tB\tC\tD\tE\tF"; my @flds = split(/\t/, $value); $flds[16] = undef; $flds[8] = 0; Dump( \@flds ); print scalar @flds, "\n", '#'x5,"\n"; 1; } or warn $@; eval { my $value = "A\tB\tC\tD\tE\tF\t\t\t\t\t\t"; my @flds = split(/\t/, $value); Dump( \@flds ); $flds[16] = undef; $flds[8] = 0; print scalar @flds, "\n", '#'x5,"\n"; 1; } or warn $@; __END__

      I've updated my post. The part about "past the end of the array" was completely wrong and is now stricken.

      I didn't originally try without the trailing tabs. I have now done so and it works fine for me too.

      — Ken

Re^2: split problem
by Anonymous Monk on Nov 29, 2016 at 23:25 UTC

    You're getting the error because you're attempting to assign a value to an element past the end of the array.

    There is no such error in perl, arrays don't have end, this is a bug

      "There is no such error in perl, arrays don't have end ..."

      Quite correct. I have stricken what I wrote from my post.

      — Ken

      Yep:

      perl -wMstrict -E 'my @a; $a[16]=0; say @a;'