in reply to Re^2: re-key a hash (not so clear)
in thread re-key a hash

/msg BrowserUk Turn on your chatterbox nodelet

My point (which includes a smiley) is that the left-hand side should be evaluated enough to give us full context (including how many slots we will be assigning into) before the right-hand side code is run in that context.

- tye        

Replies are listed 'Best First'.
Re^4: re-key a hash (not so clear)
by BrowserUk (Patriarch) on Aug 03, 2004 at 10:06 UTC

    /msg tye Sorry. I forgot how to.

    It sounds like your arguing for defining the execution order?

    If so, (apart from that I doubt it will ever happen), then I'd have to argue for the right-hand side of the = always being fully evaluated before the left-hand side is even considered, with the exception of context.

    Now I realise that there is some precedent for at least partially evaluating the left-hand side with split.

    ( $one, $two, $three ) == split '', huge_megabyte_scalar;
    makes good use of this to avoid a lot of work and memory.

    But if it is

    $#a = 10; @a = split'', $huge_long scalar;

    that doesn't (and couldn't) limit the split.

    In the first case, the knowledge of the left-hand side used in evaluating the right-hand side is purely an optimisation--effectively, extended context--which doesn't change the semantic outcome of the statement. Only the performance.

    In the case of

    @hash{ listGenerator() } = ....;

    pre-determining the affected slice of the hash prior to evaluating the right-hand side of the assignment can distinctly change the semantics which I think will always be a bad thing.

    While I'd prefer clearly defined orders of evaluation, if it happened, then the right-hand side of assignment should always be (fully) evaluated before the left-hand side, except for those rare semantically benign situations where extend contextual information results in transparent optimisations.

    Any situation where predetermined context or sub evaluation could actually determine the outcome of the statement, as would be the case if the range expression in

    @hash{ 1 .. keys %hash } = delete @hash{ listGenerator() };

    was done prior to the delete, would be a nightmare.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
      In the first case, the knowledge of the left-hand side used in evaluating the right-hand side is purely an optimisation--effectively, extended context--which doesn't change the semantic outcome of the statement.
      quibble: it does change the semantic outcome. The game is judged to be worth the candle, though. Example:
      use Data::Dumper; my ($a,$b,@a); ($a,$b) = split / /, "a "; print Dumper $a,$b; ($a,$b) = @a = split / /, "a "; print Dumper $a,$b;
      Without the optimization, the default removal of trailing empty fields leaves $b undefined.

        Conceeded++.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

      I'm not sure what strange interpretation you are doing.

      In the first case, the knowledge of the left-hand side used in evaluating the right-hand side is purely an optimisation--effectively, extended context--which doesn't change the semantic outcome of the statement. Only the performance.

      And that's all I'm talking about doing.

      Your split example makes no sense. Here's an example that makes sense:

      my @h; my @i= (0..1); @h[@i]= split / /, "This is a test case"; print "(@h)\n"; __END__ Output: (This is)

      The only difference with my proposed change is that split can be optimized in this case. No difference in output.

      You'll have to actually describe how you thought I was proposing that refined context change outcome. I'm proposing that the evalation order be changed which would change the results of statements that depend on the evaluation order, obviously. But the refinement of the "context" from "list, unspecified size" to "list, size of $N" for those rare operations that care about such things is part of the justification for this change, not something that will change outcomes itself.

      - tye        

        Okay. The example was bad. The intent was to show that if the value of something that is used on the right-hand side of the assignment, that can affect the semantic outcome of the statement, can be changed by the left-hand side of the assignment; then pre-evaluating that value would be an unsafe optimisation:

        (crudely) adapting your example:

        my @h; my @i= (0..1); @h[@i]= split //, $i[ 2 ]= "03"; print "(@h)\n"; __END__ Use of uninitialized value in join or string at P:\test\junk.pl line 4 +. Use of uninitialized value in join or string at P:\test\junk.pl line 4 +. (0 3 )

        This shows that the value of @i used on the left-hand side is not evaluated until after the right-hand side has been completed.

        I contend that this is the same logic as happens currently with

        my %h; @h{ map{ int rand 100 } 1..4 } = 'A'..'D'; print 'Before:', %h, $/; @h{ 1 .. keys %h } = delete @h{ keys %h }; print 'After: ', %h, $/; __END__ Before:25A39D0C23B After:

        The reason no output is produce after the assignment is because the value of scalar keys %h used on the left-hand side is not determined until after the right-hand side has be completed.

        Hence, the delete has taken place, it's value 0, the range generates an empty list and %h is empty.

        I (mis?)read your "it's a bug" post to mean that you felt that the extent of the range should be determined before the delete took place, so that the result of the statemant was as if

        my %h; @h{ map{ int rand 100 } 1..4 } = 'A'..'D'; print 'Before:', %h, $/; my $keys = keys %h; @h{ 1 .. $keys } = delete @h{ keys %h }; print 'After: ', %h, $/; __END__ Before:6D59B60A75C After: 4C1D3A2B

        However, looking back I see that I had missed the (somewhat detached) smiley, and misinterpreted your irony. So...no harm done.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon