[33119] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 4395 Volume: 11

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Sat Mar 21 09:09:21 2015

Date: Sat, 21 Mar 2015 06:09:05 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Sat, 21 Mar 2015     Volume: 11 Number: 4395

Today's topics:
    Re: An error on page 142 of The Camel Book. <kaz@kylheku.com>
    Re: An error on page 142 of The Camel Book. <kaz@kylheku.com>
    Re: An error on page 142 of The Camel Book. <rweikusat@mobileactivedefense.com>
    Re: An error on page 142 of The Camel Book. <rweikusat@mobileactivedefense.com>
    Re: Error Messages <edgrsprj@ix.netcom.com>
    Re: Error Messages <rweikusat@mobileactivedefense.com>
    Re: Error Messages <jurgenex@hotmail.com>
    Re: Error Messages <edgrsprj@ix.netcom.com>
    Re: Error Messages <jurgenex@hotmail.com>
    Re: Error Messages <see.my.sig@for.my.address>
    Re: Error Messages <hjp-usenet3@hjp.at>
    Re: Error Messages <from_usenet_2014@wasell.user32.com>
        Lexical Variables In Loops <see.my.sig@for.my.address>
    Re: Lexical Variables In Loops (Jens Thoms Toerring)
        Wait, lexical variables in loops do NOT always realloca <see.my.sig@for.my.address>
    Re: Wait, lexical variables in loops do NOT always real <hjp-usenet3@hjp.at>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Fri, 20 Mar 2015 19:35:02 +0000 (UTC)
From: Kaz Kylheku <kaz@kylheku.com>
Subject: Re: An error on page 142 of The Camel Book.
Message-Id: <20150320121814.890@kylheku.com>

On 2015-03-20, Rainer Weikusat <rweikusat@mobileactivedefense.com> wrote:
> "G.B." <bauhaus@futureapps.invalid> writes:
>> On 20.03.15 16:10, Rainer Weikusat wrote:
>>> The for(;;) construct reflects that fact that someone (at some time in
>>> the past) considered "last statement before the loop" and "last
>>> statement in the loop body" 'somehow special' and because of that, chose
>>> to move the 'last statement in front of the loop' into the loop head so
>>> that it's no longer in front of it and the last statement of the loop
>>> body into the loop head so that it no longer the last statement of the
>>> loop body.
>>
>> If it is possible to express every iterative construct
>> as the triple of that state transition in "for(;;)"
>> (tricky, I guess, in some cases), is there any other way
>> of doing so in Perl?
>
> There are no 'state transitions' in for (;;). The (pseudo-)Perl equivalent of
>
> for (<ex0>; <ex1>; <ex2>) { <ex3>; }
>
> is
>
><ex0>;
> {
> 	last unless <ex1>;
>         <ex3>;
>         <ex2>;
>         redo;
> }

Yes, and it is also the equivalent of this C:

  ex0;
redo:
  {
    if (!ex1)
      goto last;
    ex3
    ex2
    goto redo;
  }
last:
 ;

So what? All control structures reduce to a graph of labels, ifs
and gotos.

Yes, the for thing is fairly thin syntactic sugar. Still, it has some
assurances like that "break" and "continue" are automatically associated with
the inner-most containing loop, so no programmer-generated labels are required
where that is the desired behavior.

When the compiler expands the syntactic sugar, it has to invent some labels
that lexically don't interfere with any goto labels, and translate all
instances of "break" and "continue" into branches to those labels.

Thus

 for (A; B; C) {
   X;
   if (Y)
     continue;
   else if (Z)
     break;
   W;
 }

cannot be entirely treated by a naive textual reshuffling. It has to
be something like:

    A;

  LBL0001:
    if (B)
    {
      X;
      if (Y)
        goto LBL0002;  /* continue; */
      else if (Z)
        goto LBL0003;  /* break; */
      Z;

    LBL0002:
      C;
      goto LBL0001:
    }

  LBL0003:
     ;

The compiler has to walk the body of the loop and rewrite the "break"
and "continue" into branches to the specific labels of the loop's instance.
(Or do some other equivalent treatment to obtain the same end result.)

So for does some semi-worthwhile things that cannot be implemented by
a macro that just "teleports" pieces of code, to borrow your word.

> Any algorithm which can textually be expressed in this way can also be
> put into the for-line, ie, for (;;) can always be used to express "Well,

Any algorithm can also be computed either by a side-effect free partial
recursive function, or else a Universal Turing Machine with a tape.


------------------------------

Date: Fri, 20 Mar 2015 19:43:28 +0000 (UTC)
From: Kaz Kylheku <kaz@kylheku.com>
Subject: Re: An error on page 142 of The Camel Book.
Message-Id: <20150320123531.621@kylheku.com>

On 2015-03-20, Rainer Weikusat <rweikusat@mobileactivedefense.com> wrote:
> 	9.6 For statement
> 	   The for statement has the form
> 	         for (expression-1[opt]; expression-2[opt]; expression-3[opt]) statement
>    
> 	This statement is equivalent to
>
> 	        expression-1;
> 	        while ( expression-2 ) {
> 	                  statement
> 	                  expression-3 ;
> 		}

This equivalence is not a *defining* equivalence because it is not correct
in all cases. It has only some tutorial value for newbies.

It is not correct when the body of the for contains a "continue;".

It has another issue: the expressions are all optional in the for loop. But the
expression-2 in the while loop is *not* optional. So the naive transliteration
will fail in that case, producing a while () syntax error.
A missing expression-2 must be translated to a while (1) or similar.

> 	Thus the first expression specifies initialization for the loop;
> 	the second specifies a test, made before each iteration, such
> 	that the loop is exited when the expression becomes 0; the third
> 	expression typically specifies an incrementation which is
> 	performed after each iteration.

These "typicallys" from its designer can be indicated as giving its
intent.


------------------------------

Date: Fri, 20 Mar 2015 22:14:18 +0000
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Subject: Re: An error on page 142 of The Camel Book.
Message-Id: <87sicz1flx.fsf@doppelsaurus.mobileactivedefense.com>

Kaz Kylheku <kaz@kylheku.com> writes:
> On 2015-03-20, Rainer Weikusat <rweikusat@mobileactivedefense.com> wrote:
>> "G.B." <bauhaus@futureapps.invalid> writes:
>>> On 20.03.15 16:10, Rainer Weikusat wrote:
>>>> The for(;;) construct reflects that fact that someone (at some time in
>>>> the past) considered "last statement before the loop" and "last
>>>> statement in the loop body" 'somehow special' and because of that, chose
>>>> to move the 'last statement in front of the loop' into the loop head so
>>>> that it's no longer in front of it and the last statement of the loop
>>>> body into the loop head so that it no longer the last statement of the
>>>> loop body.
>>>
>>> If it is possible to express every iterative construct
>>> as the triple of that state transition in "for(;;)"
>>> (tricky, I guess, in some cases), is there any other way
>>> of doing so in Perl?
>>
>> There are no 'state transitions' in for (;;). The (pseudo-)Perl equivalent of
>>
>> for (<ex0>; <ex1>; <ex2>) { <ex3>; }
>>
>> is
>>
>><ex0>;
>> {
>> 	last unless <ex1>;
>>         <ex3>;
>>         <ex2>;
>>         redo;
>> }
>
> Yes, and it is also the equivalent of this C:
>
>   ex0;
> redo:
>   {
>     if (!ex1)
>       goto last;
>     ex3
>     ex2
>     goto redo;
>   }
> last:
>  ;
>
> So what?

for (;;) doesn't define any meaning for either the first or the third
expression, just a point of evaluation: The first expression will be
evaluated immediately before the first test of the loop condition/
evaluation of the second expression, the third will be evaluated after
anything else making up the loop body (despites it's in front of the
loop body).

[...]

> Yes, the for thing is fairly thin syntactic sugar. Still, it has some
> assurances like that "break" and "continue"

[...]

> So for does some semi-worthwhile things that cannot be implemented by
> a macro that just "teleports" pieces of code, to borrow your word.

Since it's a while-loop which sucked up some statements someone left
laying around in dangerously close places, it behaves like a while
loop wrt other elements of the language.

>> Any algorithm which can textually be expressed in this way can also be
>> put into the for-line, ie, for (;;) can always be used to express "Well,
>
> Any algorithm can also be computed either by a side-effect free partial
> recursive function, or else a Universal Turing Machine with a tape.

While the first expression can be used to assign a value to a loop
variable, it doesn't have to. While the third expression can be used to
modify the same variable, it also doesn't have to. While the second
expression might test the value of this variable, it doesn't have
to. These are all just informal conventions about "what people usually
put into any of these places", nothing inherent to the construct
itself. And Perl is somewhat lest restricted than C in this respect. Eg,
this little Perl program prints the first 10 blocks of 10 characters
appearing on its standard input (unless there isn't that much data
available)

----------
for ($/ = \10; <>; $. - 10 or last) {
    print;
    print "\n-\n";
}
----------


------------------------------

Date: Fri, 20 Mar 2015 22:55:29 +0000
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Subject: Re: An error on page 142 of The Camel Book.
Message-Id: <87oann1dpa.fsf@doppelsaurus.mobileactivedefense.com>

Kaz Kylheku <kaz@kylheku.com> writes:
> On 2015-03-20, Rainer Weikusat <rweikusat@mobileactivedefense.com> wrote:
>> 	9.6 For statement
>> 	   The for statement has the form
>> 	         for (expression-1[opt]; expression-2[opt]; expression-3[opt]) statement
>>    
>> 	This statement is equivalent to
>>
>> 	        expression-1;
>> 	        while ( expression-2 ) {
>> 	                  statement
>> 	                  expression-3 ;
>> 		}

[...]

>>  the third expression typically specifies an incrementation which is
>>  performed after each iteration.
>
> These "typicallys" from its designer can be indicated as giving its
> intent.

Indirectly insofar the designer's use of the construct (one hopes)
reflects what the designer considered it useful for, but it's really
just an observation: Since C doesn't have a construct which supports
looping over a range of integers, yet, people are used to such
constructs, they tend to emulate this as

for (i = 0; i < 1024; ++i);

despite this doesn't make much sense because it ends up as

i = 0;
while (i < 1024) {
	.
        .
        ++i;
}

while the counting loop should really be

i = 0;
do {
	.
        .
        .
} while (++i < 1024);

ie, it should have the test at the end because the initial value of i is
known to be less than 1024.

That's actually a nice of example of habits asserting themselves despite
they don't make any sense: I'm used to writing all of the counting loop
stuff on the initial line, hence, I write

for (i = 0; i < 1024; i++)

in C and that it doesn't really mean what I meant to express bothers me
not. Fast forward fourty years and world-famous for-slingers forgot that
loops which always execute at least once ever existed as syntactical
construct.




------------------------------

Date: Fri, 20 Mar 2015 15:21:56 -0500
From: "E.D.G." <edgrsprj@ix.netcom.com>
Subject: Re: Error Messages
Message-Id: <f-ydnRgj-77zHJHInZ2dnUU7-amdnZ2d@earthlink.com>

"gamo" <gamo@telecable.es> wrote in message 
news:megoe1$mri$1@speranza.aioe.org...
> El 20/03/15 a las 09:18, E.D.G. escribió:
>> Error Messages Question
>>
>>        Is there a command that can be inserted at the start of a Perl
>> language program that will cause compilation error messages to be sent
>> to a text file instead of being displayed on the computer screen?

> What you want is to redirect standard error to a file.
> That must be covered in your Windows and DOS manuals.

       Thanks for the information.  I do have an old DOS manual and will 
have to do some reading to see what it says about that.

E.D.G.



------------------------------

Date: Fri, 20 Mar 2015 20:36:15 +0000
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Subject: Re: Error Messages
Message-Id: <87zj771k5c.fsf@doppelsaurus.mobileactivedefense.com>

"E.D.G." <edgrsprj@ix.netcom.com> writes:
> "gamo" <gamo@telecable.es> wrote in message
> news:megoe1$mri$1@speranza.aioe.org...
>> El 20/03/15 a las 09:18, E.D.G. escribió:
>>> Error Messages Question
>>>
>>>        Is there a command that can be inserted at the start of a Perl
>>> language program that will cause compilation error messages to be sent
>>> to a text file instead of being displayed on the computer screen?
>
>> What you want is to redirect standard error to a file.
>> That must be covered in your Windows and DOS manuals.
>
>       Thanks for the information.  I do have an old DOS manual and
> will have to do some reading to see what it says about that.

JFTR: You can also use code like this,

---------
open(STDERR, '>', '/tmp/err');
die("Hugo");
---------

to redirect the standard error output to a file or

---------
open(STDOUT, '>', '/tmp/output');
open(STDERR, '>&', \*STDOUT);

print("Theodor\n");
die("Adelheid");
---------

to do this for both stderr and stdout.


------------------------------

Date: Fri, 20 Mar 2015 13:41:30 -0700
From: Jürgen Exner <jurgenex@hotmail.com>
Subject: Re: Error Messages
Message-Id: <ed1pga5bniq6tmcp9lst64fhbdcpro67d0@4ax.com>

Rainer Weikusat <rweikusat@mobileactivedefense.com> wrote:
>"E.D.G." <edgrsprj@ix.netcom.com> writes:
>> "gamo" <gamo@telecable.es> wrote in message
>> news:megoe1$mri$1@speranza.aioe.org...
>>> El 20/03/15 a las 09:18, E.D.G. escribió:
>>>> Error Messages Question
>>>>
>>>>        Is there a command that can be inserted at the start of a Perl
>>>> language program that will cause compilation error messages to be sent
>>>> to a text file instead of being displayed on the computer screen?
>>
>>> What you want is to redirect standard error to a file.
>>> That must be covered in your Windows and DOS manuals.
>>
>>       Thanks for the information.  I do have an old DOS manual and
>> will have to do some reading to see what it says about that.
>
>JFTR: You can also use code like this,
>
>---------
>open(STDERR, '>', '/tmp/err');
>die("Hugo");
>---------
>
>to redirect the standard error output to a file or

For runtime errors, yes.
But it wouldn't help with compilation errors as the OP asked about.

jue


------------------------------

Date: Fri, 20 Mar 2015 15:53:13 -0500
From: "E.D.G." <edgrsprj@ix.netcom.com>
Subject: Re: Error Messages
Message-Id: <2cWdnRIT6qgqFZHInZ2dnUU7-RudnZ2d@earthlink.com>

"Jürgen Exner" <jurgenex@hotmail.com> wrote in message 
news:b4coga5mjlgvnoo14v7e54ehctipmparhu@4ax.com...
> "E.D.G." <edgrsprj@ix.netcom.com> wrote:
>>Error Messages Question
>>
>>       Is there a command that can be inserted at the start of a Perl
>>language program that will cause compilation error messages to be sent to 
>>a
>>text file instead of being displayed on the computer screen?
>
> No, that is technically impossible.
> A program has to be compiled successfully before it can be started. Any
> compilation error would prevent this start in the first place.
>
> But what is wrong with simply redirecting the output of the compiler to
> the desired text file? Why doesn't that work for you?
>
>>       When the Perl language programs are run from a Windows computer
>>screen any error messages disappear so quickly they cannot be seen.
>
> Why don't you just scroll back up? Or are you getting that many error
> messages that they disappear from the screen buffer? If so then you may
> want to increase the "Height" of that screen buffer.

       It would be my expectation that many Windows users who run Perl 
programs start the programs by double clicking on the program name.  And 
when you do that the DOS screen is active only as long as the program is 
running.  If the program fails to compile the screen and any error messages 
disappear in a fraction of a second.

      For error checking over the years I created a number of fairly 
elaborate specialty programs.  One involves using a DO command in a small 
Perl program that calls another main program.  It lets a person actually add 
code to then main program while it is still in memory if it compiled on the 
first attempt.  If there is an error in the new code then when the DO 
command is executed again the main program simply refuses to compile.  And 
control returns to the small Perl program that continues to run.  But the 
main program's compilation error messages are not usually visible.

       The reason for using a program like that is because it can take one 
of my Perl programs a very long time to do some probability calculations. 
And this way all of those data remain in memory.  It is not necessary to do 
the calculations from scratch each time code is added to the program.

       Another specialty program that makes it possible to see Perl 
compilation error messages is a Windows batch file (.bat) that tells Windows 
to drop down to a DOS screen.  And it then automatically starts the Perl 
program.  The batch file contains a "Pause" statement that forces the DOS 
screen to remain active and display any error messages until a key is 
pressed.  Then it disappears and the Windows screen is active again.

       Perl programs can also be started from the Windows Run command.  Or 
you can use "Command Prompt" to drop down to a DOS screen that will remain 
active until you type in "Exit" and hit the Enter key.

       It sounds like the way to deal with this is to add some additional 
code to that batch file so that it redirects error messages to a text file. 
That shouldn't be too difficult.

E.D.G.



------------------------------

Date: Fri, 20 Mar 2015 14:34:27 -0700
From: Jürgen Exner <jurgenex@hotmail.com>
Subject: Re: Error Messages
Message-Id: <8f3pgapstlen65jsl06v6hhal015tbdkn2@4ax.com>

"E.D.G." <edgrsprj@ix.netcom.com> wrote:
>"Jürgen Exner" <jurgenex@hotmail.com> wrote in message 
>news:b4coga5mjlgvnoo14v7e54ehctipmparhu@4ax.com...
>> "E.D.G." <edgrsprj@ix.netcom.com> wrote:
>>>Error Messages Question
>>>
>>>       Is there a command that can be inserted at the start of a Perl
>>>language program that will cause compilation error messages to be sent to 
>>>a
>>>text file instead of being displayed on the computer screen?
>>
>> No, that is technically impossible.
>> A program has to be compiled successfully before it can be started. Any
>> compilation error would prevent this start in the first place.
>>
>> But what is wrong with simply redirecting the output of the compiler to
>> the desired text file? Why doesn't that work for you?
>>
>>>       When the Perl language programs are run from a Windows computer
>>>screen any error messages disappear so quickly they cannot be seen.
>>
>> Why don't you just scroll back up? Or are you getting that many error
>> messages that they disappear from the screen buffer? If so then you may
>> want to increase the "Height" of that screen buffer.
>
>       It would be my expectation that many Windows users who run Perl 
>programs start the programs by double clicking on the program name.  And 
>when you do that the DOS screen is active only as long as the program is 
>running.  If the program fails to compile the screen and any error messages 
>disappear in a fraction of a second.

"Doctor, each time I do this is hurts"
"Well, then don't do that"

I would assume that competent programmers know how to start a Perl
program such that the "DOS screen" does not disappear.
And I would assume that Windows users would never face a program that
still contains compiler(!!!) errors.

[some rather 'creative' ideas including user-modified code snipped]

jue


------------------------------

Date: Fri, 20 Mar 2015 20:29:04 -0700
From: Robbie Hatley <see.my.sig@for.my.address>
Subject: Re: Error Messages
Message-Id: <CKudnQwkh_AdeJHInZ2dnUVZ57ydnZ2d@giganews.com>


On 3/20/2015 1:18 AM, E.D.G. wrote:

> Error Messages Question
>
> Is there a command that can be inserted at the start of a Perl
> language program that will cause compilation error messages to
> be sent to a text file instead of being displayed on the
> computer screen?

No, because if there are any compilation errors, the program
(including the code to print errors) will never run.

My guess is, you're launching Perl programs by double-clicking
icons? If so, don't do that. I don't have that problem myself,
because I run all Perl scripts by typing the script name
at a Cygwin Bash command prompt.

Get Cygwin and use Cygwin's Bash and Perl, and launch your
scripts from that. Compile errors will never "disappear"
that way; they'll be the right there on your screen for you
to see.

And you can use Bash's redirects if you want to
redirect them to a file. I see another respondent gave
the code for that:

perl ~/scripts/util/myscript.perl 2> error.log

Or, if you start your Perl scripts with
#! /usr/bin/perl
(or whatever your path to Perl is)
you can write:

myscript.perl 2> error.log



-- 
Cheers,
Robbie Hatley
Midway City, CA, USA
perl -le 'print "\154o\156e\167o\154f\100w\145ll\56c\157m"'
http://www.well.com/user/lonewolf/
https://www.facebook.com/robbie.hatley


------------------------------

Date: Sat, 21 Mar 2015 11:53:10 +0100
From: "Peter J. Holzer" <hjp-usenet3@hjp.at>
Subject: Re: Error Messages
Message-Id: <slrnmgqjcm.fpe.hjp-usenet3@hrunkner.hjp.at>

On 2015-03-21 03:29, Robbie Hatley <see.my.sig@for.my.address> wrote:
> On 3/20/2015 1:18 AM, E.D.G. wrote:
>
>> Error Messages Question
>>
>> Is there a command that can be inserted at the start of a Perl
>> language program that will cause compilation error messages to
>> be sent to a text file instead of being displayed on the
>> computer screen?
>
> No, because if there are any compilation errors, the program
> (including the code to print errors) will never run.

That's not quite true. In Perl the compilation and execution of a
program are not as neatly separated as in for example, C or Java.
Instead the during startup the perl interpreter is continually switching
between compiling some code and executing it. Without going into the
gory details, there are two places to put code which will be executed
before the "main program" starts:

1) Code in a BEGIN block is always exectuted as soon as the block is
   compiled. So you can write something like this:

    #!/usr/bin/perl
    BEGIN {
        open STDERR, ">", "foo.log"
    }

    use warnings;
    use strict;

    $x = 23 # <-- error here
    __END__

2) Code of at the top level of a module is executed as soon as the
   module is compiled. So this works as well:

    #!/usr/bin/perl
    use redirect_stderr;

    use warnings;
    use strict;

    $x = 23
    __END__

    # redirect_stderr.pm:
    use warnings;
    use strict;
    open STDERR, ">", "foo2.log";
    1;

> And you can use Bash's redirects if you want to redirect them to a
> file. I see another respondent gave the code for that:

I agree that redirecting stderr before perl even start is almost always
the way to go.

        hp


-- 
   _  | Peter J. Holzer    | Fluch der elektronischen Textverarbeitung:
|_|_) |                    | Man feilt solange an seinen Text um, bis
| |   | hjp@hjp.at         | die Satzbestandteile des Satzes nicht mehr
__/   | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel


------------------------------

Date: Sat, 21 Mar 2015 13:12:53 +0100
From: Wasell <from_usenet_2014@wasell.user32.com>
Subject: Re: Error Messages
Message-Id: <MPG.2f777e9d17985e8d9896a1@news.eternal-september.org>

On Fri, 20 Mar 2015 03:18:10 -0500, in article <BKOdnaGdbLEjSpbInZ2dnUU7-
LudnZ2d@earthlink.com>, E.D.G. wrote:
> 
> Error Messages Question
> 
>        Is there a command that can be inserted at the start of a Perl 
> language program that will cause compilation error messages to be sent to a 
> text file instead of being displayed on the computer screen?

Yes, but as others have stated, this is not the proper way to do things.

#!/usr/bin/perl 

BEGIN { open STDERR, '>', 'errdump.txt' }

%&/()=?

After running, 'errdump.txt' will contain the error message.


------------------------------

Date: Fri, 20 Mar 2015 20:32:49 -0700
From: Robbie Hatley <see.my.sig@for.my.address>
Subject: Lexical Variables In Loops
Message-Id: <oqWdnSz_jvr8e5HInZ2dnUVZ57ydnZ2d@giganews.com>

#! /usr/bin/perl
#  ~/scripts/test/lexical-var-test.perl

=pod

On page 373 of The Camel Book, 4th ed, pdf version, I see this text:

~~~~~~~~ BEGIN QUOTE ~~~~~~~~~

 ... Finally, the following dangerous-looking code actually works fine:

for $i (1..10) {
    my @array = somefunc($i);
    $AoA[$i] = \@array;
}

That’s because the lexically scoped my @array variable is created
afresh on each pass through the loop. So even though it looks as
though you’ve stored the same variable reference each time, you
haven’t. This is a subtle distinction, but the technique can
produce more efficient code—at the risk of misleading less-enlightened
programmers. (It’s more efficient because there’s no copy in the final
assignment.) ...

~~~~~~~~ END QUOTE ~~~~~~~~~

I find that puzzling because I'd thought that a lexical variable near
the top of a loop was only declared and defined ONCE, on the line(s)
that declare and define it. I'd thought the program below would print
30 rows of "10":

=cut

use v5.014.004;
use strict;
use warnings;
our @array1;
our @array2;
our @array3;
my $j = 0;
for my $i (1..10) {
    my $var = $i; # Declares & defines $var on first pass only?
       $j   = $i; # Declares & defines $j   on first pass only?
    $array1[$i] = \$var;
    $array2[$i] = \$i;
    $array3[$i] = \$j;
}
say ${$array1[$_]} for (1..10); # prints 10, 10 times?
say ${$array2[$_]} for (1..10); # prints 10, 10 times?
say ${$array3[$_]} for (1..10); # prints 10, 10 times?

=pod

But what it *actually* prints is:

Aragorn@Ketch
/rhe/src/test
%lexical-var-test.perl
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
10
10
10
10
10
10
10
10
10
10

Aragorn@Ketch
/rhe/src/test
%

Which much astounds me. This points out a huge error in my thinking
about lexical variables declared in loops and in loop headers; not
only are they redefined each time the loop is started, but they're
redefined (new, different memory allocated) *each loop iteration*.

Is the same true in C?
Let's find out:

/* lexical-var-test.c */
#include <stdio.h>
int * array1[12];
int * array2[12];
int * array3[12];
int main(int argc, char *argv[])
{
    int j = 0;
    for ( int i = 1 ; i <= 10 ; ++i ) {
       int var = i;
           j   = i;
       array1[i] = &var;
       array2[i] = &i;
       array3[i] = &j;
    }
    for ( int i = 1 ; i <= 10 ; ++i ) {
       printf("%d\n", *array1[i]);
    }
    for ( int i = 1 ; i <= 10 ; ++i ) {
       printf("%d\n", *array2[i]);
    }
    for ( int i = 1 ; i <= 10 ; ++i ) {
       printf("%d\n", *array3[i]);
    }
    return 0;
}

OK, to complile that, I had to set "-std=c99" for gcc, else it wouldn't
even compile, because modern C deprecates for(int i=0 ; i<n ; ++i); it
wants you to declare the i on the line BEFORE the for loop.

After setting -std=c99, this compiles, and when run, prints:

Aragorn@Ketch
/rhe/src/test
%lexical-var-test.exe
0
0
0
0
0
0
0
0
0
0
11
11
11
11
11
11
11
11
11
11
10
10
10
10
10
10
10
10
10
10

Aragorn@Ketch
/rhe/src/test
%

Wow. Obviously, C handles variables *very* differently than Perl.

Firstly, the "var" is obviously erased after the loop, so I can't even
test whether multiple copies or a single copy were created. All addresses
to "var" now point to something that's zero. (Or to random garbage that
just *happens* to be 0?)

The "i" still exists after the loop, but apparently only one copy existed.
It's 11 because it looped back to the top and got incremented by ++i
before failing the i<=10 test.

The "j" still exists after the loop, but apparently only one copy existed.
It's 10 because that's the highest i got inside the loop.

Apparently in C, all loop variables are "one copy only"?

Wait, I'll remove the * tokens and see what the addresses are:

Aragorn@Ketch
/rhe/src/test
%lexical-var-test.exe
2345740
2345740
2345740
2345740
2345740
2345740
2345740
2345740
2345740
2345740
2345736
2345736
2345736
2345736
2345736
2345736
2345736
2345736
2345736
2345736
2345732
2345732
2345732
2345732
2345732
2345732
2345732
2345732
2345732
2345732

Aragorn@Ketch
/rhe/src/test
%

Ok, apparently all variables exist as ONLY ONE COPY EACH in C.
It seems that C does *not* create a new copy of anything for each
iteration of a loop. Every iteration of varible x has the *same*
address, so the variable over-writes itself each iteration.
That's what I thought, actually, and I assumed that Perl was
the same.

But in Perl, apparently this is not true at all!
Apparently, when you write:

our $array;
for (1..10) {
    my $var = $_;
    push @array, \$var;
}

You're collecting 10 *different* memory addresses, because Perl
creates a new variable called $var (with a new address) for each
iteration.  I wouldn't have thunk it. Color me shocked.


-- 
Cheers,
Robbie Hatley
Midway City, CA, USA
perl -le 'print "\154o\156e\167o\154f\100w\145ll\56c\157m"'
http://www.well.com/user/lonewolf/
https://www.facebook.com/robbie.hatley


=cut




------------------------------

Date: 21 Mar 2015 10:45:18 GMT
From: jt@toerring.de (Jens Thoms Toerring)
Subject: Re: Lexical Variables In Loops
Message-Id: <cn50dsF3hjoU1@mid.uni-berlin.de>

Robbie Hatley <see.my.sig@for.my.address> wrote:
> #! /usr/bin/perl
> #  ~/scripts/test/lexical-var-test.perl

> =pod

> On page 373 of The Camel Book, 4th ed, pdf version, I see this text:

> ~~~~~~~~ BEGIN QUOTE ~~~~~~~~~

> ... Finally, the following dangerous-looking code actually works fine:

> for $i (1..10) {
>     my @array = somefunc($i);
>     $AoA[$i] = \@array;
> }

> That’s because the lexically scoped my @array variable is created
> afresh on each pass through the loop. So even though it looks as
> though you’ve stored the same variable reference each time, you
> haven’t. This is a subtle distinction, but the technique can
> produce more efficient code—at the risk of misleading less-enlightened
> programmers. (It’s more efficient because there’s no copy in the final
> assignment.) ...

> ~~~~~~~~ END QUOTE ~~~~~~~~~

> I find that puzzling because I'd thought that a lexical variable near
> the top of a loop was only declared and defined ONCE, on the line(s)
> that declare and define it. I'd thought the program below would print
> 30 rows of "10":

> =cut

> use v5.014.004;
> use strict;
> use warnings;
> our @array1;
> our @array2;
> our @array3;
> my $j = 0;
> for my $i (1..10) {
>     my $var = $i; # Declares & defines $var on first pass only?
>        $j   = $i; # Declares & defines $j   on first pass only?
>     $array1[$i] = \$var;
>     $array2[$i] = \$i;
>     $array3[$i] = \$j;
> }

Here two local variabless, $var and $i. What you do with them
is creating references to them and store them in the non-local
array. And once you have done that there now exist 2 references
to each of them, one in the loop and one in something that is
non-local. At the end of the block one of the references gets
deleted, the one to $var and $i. But the others still exist. So
the nex time round $var and $imust be something different since
what tey were before is now what's stored in the non-local array.

As the text indicates, it could also have been done differently:
The same locations might have been reused for $var and $i. But
then e.g.

   $array1[$i] = \$var;

would have required that a new variable is created for the
reference stored in array1 and the value copied over to it.
The way it's done in reality is a bit more efficient since
no copy needs to be done. Not a big win probably when dealing
with scalars, but if references to large local arrays are pro-
duced, saving a complete copy operation might have a much larger
impact and the local array doesn't need to be cleared out (only
a new, uninitialized array needs to be created for the local
array variable).

On the other hand,  what you store in array3 is always the same
reference to $j - it doesn't go out of scope at the end of the
loops block so there's no need to change anything abut it - at
the end you have 11 references to $j, all pointing to the same
Perl variable with the last assigned value.

                             Regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de


------------------------------

Date: Sat, 21 Mar 2015 01:28:21 -0700
From: Robbie Hatley <see.my.sig@for.my.address>
Subject: Wait, lexical variables in loops do NOT always reallocate per-iteration.
Message-Id: <IuadnW2wZeg5tpDInZ2dnUVZ572dnZ2d@giganews.com>


I'd quoted page 373 of The Camel Book, 4th ed, pdf version, as saying...

> .... Finally, the following dangerous-looking code actually works fine:
>
> for $i (1..10) {
>     my @array = somefunc($i);
>     $AoA[$i] = \@array;
> }
>
> That’s because the lexically scoped my @array variable is created
> afresh on each pass through the loop...

But on further experimentation, I see that it's NOT always true that
lexical variables in loops re-allocate each iteration. They only do it
if they have non-zero ref count.

In the example above, a reference to @array is being stored in an
array-of-array-refs on each iteration, so Perl retains a copy of
@array each iteration.

HOWEVER, if the ref count of a lexical variable declared in a loop is
zero when loop bottom is reached, Perl re-uses the same memory address
like C does. So the code which The Camel Book gives above not only
LOOKS dangerous, it IS dangerous because it's misleading.

For example:

use v5.014.004;
use strict;
use warnings;
for (1..10) {
    my $var = $_;
    say("Addr(var) = ", \$var, "  Value(var) = ", $var);
}

That script prints THIS:

Addr(var) = SCALAR(0x600084e60)  Value(var) = 1
Addr(var) = SCALAR(0x600084e60)  Value(var) = 2
Addr(var) = SCALAR(0x600084e60)  Value(var) = 3
Addr(var) = SCALAR(0x600084e60)  Value(var) = 4
Addr(var) = SCALAR(0x600084e60)  Value(var) = 5
Addr(var) = SCALAR(0x600084e60)  Value(var) = 6
Addr(var) = SCALAR(0x600084e60)  Value(var) = 7
Addr(var) = SCALAR(0x600084e60)  Value(var) = 8
Addr(var) = SCALAR(0x600084e60)  Value(var) = 9
Addr(var) = SCALAR(0x600084e60)  Value(var) = 10

Same behavior as in C.

I don't know if this counts as being an "error" on page 373,
but it's certainly "misleading", because Perl doesn't always
behave in the way indicated; only if ref count is > 0.


-- 
Cheers,
Robbie Hatley
Midway City, CA, USA
perl -le 'print "\154o\156e\167o\154f\100w\145ll\56c\157m"'
http://www.well.com/user/lonewolf/
https://www.facebook.com/robbie.hatley


------------------------------

Date: Sat, 21 Mar 2015 12:26:59 +0100
From: "Peter J. Holzer" <hjp-usenet3@hjp.at>
Subject: Re: Wait, lexical variables in loops do NOT always reallocate per-iteration.
Message-Id: <slrnmgqlc3.fpe.hjp-usenet3@hrunkner.hjp.at>

On 2015-03-21 08:28, Robbie Hatley <see.my.sig@for.my.address> wrote:
> I'd quoted page 373 of The Camel Book, 4th ed, pdf version, as saying...
>> .... Finally, the following dangerous-looking code actually works fine:
>>
>> for $i (1..10) {
>>     my @array = somefunc($i);
>>     $AoA[$i] = \@array;
>> }
>>
>> That’s because the lexically scoped my @array variable is created
>> afresh on each pass through the loop...
>
> But on further experimentation, I see that it's NOT always true that
> lexical variables in loops re-allocate each iteration. They only do it
> if they have non-zero ref count.
>
> In the example above, a reference to @array is being stored in an
> array-of-array-refs on each iteration, so Perl retains a copy of
> @array each iteration.
>
> HOWEVER, if the ref count of a lexical variable declared in a loop is
> zero when loop bottom is reached, Perl re-uses the same memory address
> like C does.

Effectively yes. That's a common optimization.

> So the code which The Camel Book gives above not only
> LOOKS dangerous, it IS dangerous because it's misleading.

No, it isn't dangerous. Conceptionally, «my» creates a new variable
instance. If that variable's reference count is 0 at the end of the
block, it will be destroyed, otherwise the other references to the
variable can continue to use it safely. The next time the my is
executed, a new variable will be created.

However, in many cases destroying a variable just to recreate it
immediately again is wasteful. So if perl detects that it can safely
reuse the same variable, it will do so.

In a sense a C compiler does the same optimization: You get a new
(automatic) variable on every iteration but since it is always destroyed
at the end of the block (no reference counting or equivalent in C), it
is always "safe" for the compiler to reuse the memory.

        hp


-- 
   _  | Peter J. Holzer    | Fluch der elektronischen Textverarbeitung:
|_|_) |                    | Man feilt solange an seinen Text um, bis
| |   | hjp@hjp.at         | die Satzbestandteile des Satzes nicht mehr
__/   | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

Back issues are available via anonymous ftp from
ftp://cil-www.oce.orst.edu/pub/perl/old-digests. 

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V11 Issue 4395
***************************************


home help back first fref pref prev next nref lref last post