this should work

Discussion in 'Perl Misc' started by George Mpouras, Jul 10, 2013.

  1. foreach my $dir (qw/commands_pre commands_post/) {
    $dir = "/tmp/$dir";
    print "$dir\n"
    }

    # Modification of a read-only value attempted at ./test line 139
    George Mpouras, Jul 10, 2013
    #1
    1. Advertising

  2. George Mpouras

    Jim Gibson Guest

    In article <krkm21$19jd$>, George Mpouras
    <> wrote:

    > foreach my $dir (qw/commands_pre commands_post/) {
    > $dir = "/tmp/$dir";
    > print "$dir\n"
    > }
    >
    > # Modification of a read-only value attempted at ./test line 139


    Because of the aliasing feature of foreach loops, you are trying to
    modify the elements of qw/commands_pre commands_post/, which are not
    lvalues. Try this instead:

    #!/usr/bin/perl
    use strict;
    use warnings;

    foreach my $dir (qw/commands_pre commands_post/) {
    my $tmpdir = "/tmp/$dir";
    print "$tmpdir\n"
    }

    See 'perldoc perlsyn' and the section entitled 'Foreach Loops':

    "LABEL foreach VAR (LIST) BLOCK"

    "If any element of LIST is an lvalue, you can modify it by modifying VAR
    inside the loop. Conversely, if any element of LIST is NOT an lvalue,
    any attempt to modify that element will fail. In other words, the
    'foreach' loop index variable is an implicit alias for each item in the
    list that you're looping over."

    --
    Jim Gibson
    Jim Gibson, Jul 10, 2013
    #2
    1. Advertising

  3. it is a perl bug or bad behavior , should change.
    George Mpouras, Jul 11, 2013
    #3
  4. George Mpouras

    Tim McDaniel Guest

    In article <krlk2f$2e7e$>,
    George Mpouras <> wrote:
    >it is a perl bug or bad behavior , should change.


    I don't like it -- it's an "action at a distance spookiness" effect
    that I've found little use for. I just work around it.

    You have just had the documentation quoted and explained. It's a
    long-standing aspect of Perl. I call something a "bug" when it's a
    result that does not match the documentation, so you have no right to
    call it a "perl bug".

    "Misfeature" or "bad design": aliasing something to each item in turn,
    where changing the variable changes the underlying thing, is
    documented in several areas and decades old. If you don't like it, it
    has an immediate and obvious workaround: assign it to a temporary.

    TL;DR: Quit whining. Learn when aliasing happens and don't change
    aliased variables (unless you have a need for it).

    --
    Tim McDaniel,
    Tim McDaniel, Jul 11, 2013
    #4
  5. Jim Gibson <> writes:

    [...]

    > foreach my $dir (qw/commands_pre commands_post/) {
    > my $tmpdir = "/tmp/$dir";
    > print "$tmpdir\n"
    > }


    The perl compiler doesn't do invariant code motion because whether or
    not some code is 'invariant' cannot generally be decided at compile
    time. Because of this, the loop body above behave exactly as written
    down: For each iteration, it creates a new my variable and assigns a
    value to it. Unless there's a specific reason why this behaviour would
    be desirable, such constructs should be avoided[*].

    [*] This is also true for the more general case of 'Yes we can!'
    variable declarations: Just because a new my variable can be created
    as part of some construct doesn't mean there's a good reason why it
    should be created, not only because this takes time but more
    importantly, because it makes the code more complicated, especially as
    real world code isn't going to have nice and small two lines blocks
    but rather big and ugly 500 lines blocks with 5 hundred lines blocks
    inside and each of these further subdivided into dozens of line
    blocks (this is probably still and optimistic estimate). This makes
    for extremely 'enjoyable' variable hunting ...
    Rainer Weikusat, Jul 11, 2013
    #5
  6. George Mpouras <> wrote:
    >it is a perl bug or bad behavior , should change.


    _WHAT_ is a bug or bad behaviour in the Perl interpreter?
    Please quote sufficient context such that your postings are meaningful.

    jue
    Jürgen Exner, Jul 11, 2013
    #6
  7. Στις 11/7/2013 13:34, ο/η Jürgen Exner έγÏαψε:
    > George Mpouras <> wrote:
    >> it is a perl bug or bad behavior , should change.

    >
    > _WHAT_ is a bug or bad behaviour in the Perl interpreter?
    > Please quote sufficient context such that your postings are meaningful.
    >
    > jue
    >



    Perl is for humans so its behavior should be the expected if there is
    not a serious reason not to be
    George Mpouras, Jul 11, 2013
    #7
  8. George Mpouras <>
    writes:

    [ foreach is aliasing ]

    > Perl is for humans so its behavior should be the expected if there is
    > not a serious reason not to be


    I can't see any serious reason for Perl not to work as documented and
    designed. The feature is useful and well-documented and absolutely not a
    bug.

    //Makholm
    Peter Makholm, Jul 11, 2013
    #8
  9. the behavior is different for an @array and a hardcoded list
    George Mpouras, Jul 11, 2013
    #9
  10. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Jim Gibson <> writes:
    >>
    >> [...]
    >>
    >> > foreach my $dir (qw/commands_pre commands_post/) {
    >> > my $tmpdir = "/tmp/$dir";
    >> > print "$tmpdir\n"
    >> > }

    >>
    >> The perl compiler doesn't do invariant code motion because whether or
    >> not some code is 'invariant' cannot generally be decided at compile
    >> time.

    >
    > I don't know what you mean by that, but...


    In this case, this would be transforming the

    for (...) {
    my $tmp = 'ar!';
    }

    to

    my $tmp;
    for (...) {
    $tmp = 'ar!';
    }

    because the 'my $tmp' is invariant code: It's effective result never
    changes throughout the loop.

    >
    >> Because of this, the loop body above behave exactly as written
    >> down: For each iteration, it creates a new my variable and assigns a
    >> value to it.

    >
    > ...this is nonsense. Perl quite deliberately reuses the same variable
    > every time, to avoid the allocation overhead, unless you pass a (strong)
    > reference to it outside the loop. Try it and see:
    >
    > use Scalar::Util qw/refaddr/;
    >
    > for (1, 2, 3) {
    > my $tmp = "foo/$_";
    > say refaddr \$tmp;
    > }


    Maybe some versions of Perl do that (which would be an
    improvement). But the one I tested certainly doesn't. Assuming the
    following code

    -------------
    use Benchmark;

    sub in_loop
    {
    for (0 .. 100) {
    my $a = $_ + 1;
    }
    }

    sub out_of_loop
    {
    my $a;
    for (0 .. 100) {
    $a = $_ + 1
    }
    }

    timethese(-2,
    {
    in_loop => \&in_loop,
    out_of_loop => \&out_of_loop
    });
    -------------

    the loop in in_loop is translated to (perl -MO=Concise,in_loop, perl
    5.10.1)

    e <0> iter s ->f
    - <@> lineseq sK ->-
    7 <;> nextstate(main 596 a.pl:6) v ->8
    c <2> sassign vKS/2 ->d
    a <2> add[t5] sK/2 ->b
    - <1> ex-rv2sv sK/1 ->9
    8 <#> gvsv[*_] s ->9
    9 <$> const[IV 1] s ->a
    b <0> padsv[$a:596,597] sRM*/LVINTRO ->c
    d <0> unstack s ->e

    is what creates the variable.

    For out_of_loop, this looks like this:

    e <0> iter s ->f
    - <@> lineseq sK ->-
    9 <;> nextstate(main 601 a.pl:14) v ->a
    c <2> add[$a:600,603] sK/TARGMY,2 ->d
    - <1> ex-rv2sv sK/1 ->b
    a <#> gvsv[*_] s ->b
    b <$> const[IV 1] s ->c
    d <0> unstack s ->e

    and the padsv ... LVINTRO happens in the subroutine preamble.

    Running the program here yields the expected result that out_of_loop
    executes at about 1.43 times the speed of in_loop.

    >> Unless there's a specific reason why this behaviour would
    >> be desirable, such constructs should be avoided[*].
    >>
    >> [*] This is also true for the more general case of 'Yes we can!'
    >> variable declarations: Just because a new my variable can be created
    >> as part of some construct doesn't mean there's a good reason why it
    >> should be created, not only because this takes time but more
    >> importantly, because it makes the code more complicated, especially as
    >> real world code isn't going to have nice and small two lines blocks
    >> but rather big and ugly 500 lines blocks with 5 hundred lines blocks
    >> inside and each of these further subdivided into dozens of line
    >> blocks (this is probably still and optimistic estimate).

    >
    > Speak for yourself. *My* real-world code doesn't look like that.


    I speak for code written by people other than me I happen to know. I'm
    completely willing to believe that you either don't know any code
    written by other people or only code written by other people who are
    above-average skilled programmers and that you're one yourself,
    however, that doesn't change this observation.
    Rainer Weikusat, Jul 11, 2013
    #10
  11. On 2013-07-11 12:03, George Mpouras <> wrote:
    > the behavior is different for an @array and a hardcoded list


    Yes, for the same reason that the behaviour for $x[1] = 5 is different
    than 2 = 5: You can assign a value to an array element, but you can't
    assign a value to a constant.

    After
    my @x = (1, 2, 3);
    for (@x) {
    $_ = 5;
    }
    @x has the value (5, 5, 5), so it's basically the same as:
    $x[0] = 5;
    $x[1] = 5;
    $x[2] = 5;

    Now consider the equivalent with constants:
    for (1, 2, 3) {
    $_ = 5;
    }
    That would be the same as:
    1 = 5;
    2 = 5;
    3 = 5;
    Oops!

    hp

    --
    _ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
    |_|_) | Sysadmin WSR | Man feilt solange an seinen Text um, bis
    | | | | die Satzbestandteile des Satzes nicht mehr
    __/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
    Peter J. Holzer, Jul 11, 2013
    #11
  12. ok but this is a tautology

    for (1, 2, 3) {
    $_ = 5;
    }

    should NOT be the same as:

    1 = 5;
    2 = 5;
    3 = 5


    never mind , some things never change
    George Mpouras, Jul 11, 2013
    #12
  13. (Tim McDaniel) writes:
    > In article <krlk2f$2e7e$>,
    > George Mpouras <> wrote:


    [so-called 'aliasing in for loops']

    >>it is a perl bug or bad behavior , should change.

    >
    > I don't like it -- it's an "action at a distance spookiness" effect
    > that I've found little use for. I just work around it.


    [...]

    > "Misfeature" or "bad design":


    I think a discrepancy between your 'mental model' of 'Perl execution'
    and the way it actually works exists here: In perl, values are always
    represented as SVs ('scalars') and a SV is a pretty complex object,
    copying of which may be 'expensive', eg, the following perl code:

    ---
    use Devel::peek;

    my $s = 'string';
    my $ss = $s;

    Dump($s);
    Dump($ss);
    ---

    causes a the string assigned to s to be copied to a newly, dynamically
    allocated area of memory, as can be seen in the output generated when
    running this code:

    ---
    SV = PV(0x603b78) at 0x621188
    REFCNT = 1
    FLAGS = (PADMY,POK,pPOK)
    PV = 0x61b9f0 "string"\0
    CUR = 6
    LEN = 8
    SV = PV(0x603c38) at 0x6211b8
    REFCNT = 1
    FLAGS = (PADMY,POK,pPOK)
    PV = 0x617a10 "string"\0
    CUR = 6
    LEN = 8
    ---

    Because an SV is not really a 'value' in the sense of, say, a C
    integer or pointer, it is always passed 'by reference' into
    syntactical constructs which work with 'lists of SVs' such as map { },
    for ( ) { } or subroutine calls and it is up to the user to copy the
    'argument SV' in case an independently modifiable copy of the original
    thing is actually needed for some reason (perl supports, supported or
    was supposed to support COW-sharing of 'SV string bodies' in some
    circumstance or at some point in the in the past, but except 'somebody
    worked on that in the past', I don't really know any details about
    that). That's similar to the way Java handles this where complex
    objects are always passed 'by reference', just that Java also has
    'primitive types' which are passed by value and Perl doesn't.
    Rainer Weikusat, Jul 11, 2013
    #13
  14. George Mpouras <>
    writes:
    > ok but this is a tautology
    >
    > for (1, 2, 3) {
    > $_ = 5;
    > }
    >
    > should NOT be the same as:
    >
    > 1 = 5;
    > 2 = 5;
    > 3 = 5
    >
    >
    > never mind , some things never change


    Indeed: Perl still represents all values as SVs internally and this
    means the literal numbers exist in your source code but in the
    compiled code, they're just used to initialize read-only SVs which are
    passed by reference. That's something one just needs to be aware of
    when using Perl.
    Rainer Weikusat, Jul 11, 2013
    #14
  15. Rainer Weikusat <> writes:

    > thing is actually needed for some reason (perl supports, supported or
    > was supposed to support COW-sharing of 'SV string bodies' in some
    > circumstance or at some point in the in the past, but except 'somebody
    > worked on that in the past', I don't really know any details about
    > that).


    Copy-on-Write strings was supposed to be enabled by default for Perl
    5.18, but it broke a significant number of XS modules. It can be enabled
    by running Configer with '-Accflags=-DPERL_NEW_COPY_ON_WRITE' when
    building perl.

    I believe it is enabled in perl 5.19.

    //Makholm
    Peter Makholm, Jul 11, 2013
    #15
  16. Ben Morrow <> writes:
    >> Ben Morrow <> writes:
    >> > Quoth Rainer Weikusat <>:
    >> >> Jim Gibson <> writes:
    >> >>
    >> >> [...]
    >> >>
    >> >> > foreach my $dir (qw/commands_pre commands_post/) {
    >> >> > my $tmpdir = "/tmp/$dir";
    >> >> > print "$tmpdir\n"
    >> >> > }
    >> >>
    >> >> The perl compiler doesn't do invariant code motion because whether or
    >> >> not some code is 'invariant' cannot generally be decided at compile
    >> >> time.
    >> >
    >> > I don't know what you mean by that, but...

    >>
    >> In this case, this would be transforming the
    >>
    >> for (...) {
    >> my $tmp = 'ar!';
    >> }
    >>
    >> to
    >>
    >> my $tmp;
    >> for (...) {
    >> $tmp = 'ar!';
    >> }
    >>
    >> because the 'my $tmp' is invariant code: It's effective result never
    >> changes throughout the loop.

    >
    > But it does: logically, you get a different variable each time. That
    > transformation changes the result, since the value of $tmp will persist
    > from one iteration to the next (as well as being visible below the
    > loop).


    It doesn't because the first thing which happens in the loop body is
    an assignment overwriting the old value.

    [...]

    >> >> Because of this, the loop body above behave exactly as written
    >> >> down: For each iteration, it creates a new my variable and assigns a
    >> >> value to it.
    >> >
    >> > ...this is nonsense. Perl quite deliberately reuses the same variable
    >> > every time, to avoid the allocation overhead, unless you pass a (strong)
    >> > reference to it outside the loop. Try it and see:
    >> >
    >> > use Scalar::Util qw/refaddr/;
    >> >
    >> > for (1, 2, 3) {
    >> > my $tmp = "foo/$_";
    >> > say refaddr \$tmp;
    >> > }

    >>
    >> Maybe some versions of Perl do that (which would be an
    >> improvement). But the one I tested certainly doesn't.

    >
    > Did you actually run that bit of code? With 'say' replaced with 'print',
    > it produces the same refaddr three times on every version perl I have
    > available (back to 5.6.0).


    Let me but it this way:

    -------
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    char *p;

    p = malloc(8);
    printf("%p\n", p);
    free(p);

    p = malloc(8);
    printf("%p\n", p);
    free(p);
    return 0;
    }
    -------

    This should usually print the same value twice despite, as can be
    checked with ltrace (on Linux), it actually calls malloc and free
    twice, IOW, that two entities which exists at two different times
    happen to have the same address doesn't necessarily mean anything
    except that they happen to have the same address.



    >
    >> Assuming the
    >> following code
    >>
    >> -------------
    >> use Benchmark;
    >>
    >> sub in_loop
    >> {
    >> for (0 .. 100) {
    >> my $a = $_ + 1;
    >> }
    >> }
    >>
    >> sub out_of_loop
    >> {
    >> my $a;
    >> for (0 .. 100) {
    >> $a = $_ + 1
    >> }

    > }
    >>
    >> timethese(-2,
    >> {
    >> in_loop => \&in_loop,
    >> out_of_loop => \&out_of_loop
    >> });
    >> -------------
    >>
    >> the loop in in_loop is translated to (perl -MO=Concise,in_loop, perl
    >> 5.10.1)
    >>
    >> e <0> iter s ->f
    >> - <@> lineseq sK ->-
    >> 7 <;> nextstate(main 596 a.pl:6) v ->8
    >> c <2> sassign vKS/2 ->d
    >> a <2> add[t5] sK/2 ->b
    >> - <1> ex-rv2sv sK/1 ->9
    >> 8 <#> gvsv[*_] s ->9
    >> 9 <$> const[IV 1] s ->a
    >> b <0> padsv[$a:596,597] sRM*/LVINTRO ->c
    >> d <0> unstack s ->e
    >>
    >> is what creates the variable.
    >>
    >> For out_of_loop, this looks like this:
    >>
    >> e <0> iter s ->f
    >> - <@> lineseq sK ->-
    >> 9 <;> nextstate(main 601 a.pl:14) v ->a
    >> c <2> add[$a:600,603] sK/TARGMY,2 ->d
    >> - <1> ex-rv2sv sK/1 ->b
    >> a <#> gvsv[*_] s ->b
    >> b <$> const[IV 1] s ->c
    >> d <0> unstack s ->e
    >>
    >> and the padsv ... LVINTRO happens in the subroutine preamble.

    >
    > Ah yes, that's a *different* bit of cheating (on perl's part).


    No, it's not. It's a completely valid example of the difference
    between '[needlessly] putting my into the loop' and 'my outside of the
    loop':

    [...]

    > in the specific case of a builtin operator whose result is
    > assigned directly to an already-declared lexical, perl will optimise by
    > having the operator store its result directly in the lexical, rather
    > than using a temporary.


    [...]

    > Run your benchmark again with a sub call or something instead of the
    > addition, and I doubt you'll see any difference between the two.


    I have no doubt that you will be able to find a way to transform the
    code such that the difference I was writing about becomes unmeasurable
    because it is tiny compared to the time 'accidental operations' also
    performed in the loop need. However, 'a sub call' is not yet good
    enough. But I see little reason to climb this ladder: Nobody ever
    changed his opinion just because it was demonstrably wrong, only the
    pseudo-arguments supposed to make it appear as the rational choice
    nevertheless become more complicated.
    Rainer Weikusat, Jul 11, 2013
    #16
  17. >> Are you saying that Perl should have caught your error but failed to
    >> do so, or is that the (correct) error message from Perl?


    What about if an error occure while perl is trying correctly to catch the
    error and this fail ;
    Joking, Perl correctly catches the error (of course it is not correct, that
    this error correctly occured)
    George Mpouras, Jul 11, 2013
    #17
  18. Rainer Weikusat <> writes:

    [...]

    > I have no doubt that you will be able to find a way to transform the
    > code such that the difference I was writing about becomes
    > unmeasurable


    Just in case there's any doubt about that: Ben is - of course - right
    in claiming that Perl doesn't really create a new variable if the
    previously created one is still available for reuse, it just puts that
    back into a 'virgin' state. Which is still more work then when the
    variable has been created outside of the loop. Also, it is possible to
    write code such that it exploits other side-effects of the 'new
    variable perl loop' to make the difference more accentuated eg

    -------------
    use Benchmark;

    sub three()
    {
    return "three";
    }

    sub in_loop
    {
    for (0 .. 100) {
    my $a;
    $a = three() if $_ & 1;
    }
    }

    sub out_of_loop
    {
    my $a;
    for (0 .. 100) {
    $a = three() if $_ & 1;
    }
    }

    timethese(-2,
    {
    in_loop => \&in_loop,
    out_of_loop => \&out_of_loop
    });
    -------------

    and it is - of course - also possible to 'enhance' perl to work around
    stupidly written code harder in order to catch this as well. But
    making the compiler work harder in order to hide someone's mistakes
    better is still not exactly what I want to have given that the amount
    of work the compiler performs is also a cost wich affects me.
    Rainer Weikusat, Jul 11, 2013
    #18
  19. George Mpouras

    Keith Keller Guest

    On 2013-07-11, Rainer Weikusat <> wrote:
    >
    > In this case, this would be transforming the
    >
    > for (...) {
    > my $tmp = 'ar!';
    > }
    >
    > to
    >
    > my $tmp;
    > for (...) {
    > $tmp = 'ar!';
    > }
    >
    > because the 'my $tmp' is invariant code: It's effective result never
    > changes throughout the loop.


    This strikes me as premature optimization. Unless I know my program is
    spending too much time doing my $tmp = 'ar!'; inside the for loop, I
    would much prefer to keep $tmp properly scoped and initialized inside
    the loop.

    --keith

    --
    -francisco.ca.us
    (try just my userid to email me)
    AOLSFAQ=http://www.therockgarden.ca/aolsfaq.txt
    see X- headers for PGP signature information
    Keith Keller, Jul 11, 2013
    #19
  20. Keith Keller <-francisco.ca.us> wrote:
    >On 2013-07-11, Rainer Weikusat <> wrote:
    >> my $tmp;
    >> for (...) {
    >> $tmp = 'ar!';
    >> }
    >>
    >> because the 'my $tmp' is invariant code: It's effective result never
    >> changes throughout the loop.

    >
    >This strikes me as premature optimization. Unless I know my program is
    >spending too much time doing my $tmp = 'ar!'; inside the for loop, I
    >would much prefer to keep $tmp properly scoped and initialized inside
    >the loop.


    How very true!!!
    CPU-time is cheap, programmers time is expensive.

    jue
    Jürgen Exner, Jul 11, 2013
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jim Owen
    Replies:
    1
    Views:
    434
    Natty Gur
    Jul 24, 2003
  2. Steve Richter

    should windows 2000 smtp service work for me?

    Steve Richter, Apr 19, 2005, in forum: ASP .Net
    Replies:
    0
    Views:
    332
    Steve Richter
    Apr 19, 2005
  3. ~~~ .NET Ed ~~~

    How should control images should be handled?

    ~~~ .NET Ed ~~~, Oct 31, 2004, in forum: ASP .Net Building Controls
    Replies:
    1
    Views:
    218
    John Saunders
    Nov 3, 2004
  4. Josef 'Jupp' SCHUGT

    What the FAQs should and should not contain

    Josef 'Jupp' SCHUGT, Aug 19, 2005, in forum: Ruby
    Replies:
    0
    Views:
    176
    Josef 'Jupp' SCHUGT
    Aug 19, 2005
  5. botp
    Replies:
    6
    Views:
    192
    Joel VanderWerf
    Oct 5, 2010
Loading...

Share This Page