Velocity Reviews > Perl > this should work

this should work

Peter J. Holzer
Guest
Posts: n/a

 07-11-2013
On 2013-07-11 12:03, George Mpouras <(E-Mail Removed) m> 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
| | | http://www.velocityreviews.com/forums/(E-Mail Removed) | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel

George Mpouras
Guest
Posts: n/a

 07-11-2013
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

Rainer Weikusat
Guest
Posts: n/a

 07-11-2013
(E-Mail Removed) (Tim McDaniel) writes:
> In article <krlk2f\$2e7e\$(E-Mail Removed)>,
> George Mpouras <(E-Mail Removed) m> 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.

[...]

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:eek;

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(0x603b7 at 0x621188
REFCNT = 1
PV = 0x61b9f0 "string"\0
CUR = 6
LEN = 8
SV = PV(0x603c3 at 0x6211b8
REFCNT = 1
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
Guest
Posts: n/a

 07-11-2013
George Mpouras <(E-Mail Removed) m>
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.

Peter Makholm
Guest
Posts: n/a

 07-11-2013
Rainer Weikusat <(E-Mail Removed)> 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

Rainer Weikusat
Guest
Posts: n/a

 07-11-2013
Ben Morrow <(E-Mail Removed)> writes:
>> Ben Morrow <(E-Mail Removed)> writes:
>> > Quoth Rainer Weikusat <(E-Mail Removed)>:
>> >> Jim Gibson <(E-Mail Removed)> 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:
>> >
>> >
>> > for (1, 2, 3) {
>> > my \$tmp = "foo/\$_";
>> > }

>>
>> 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(;
printf("%p\n", p);
free(p);

p = malloc(;
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
>>
>> [b] 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.

George Mpouras
Guest
Posts: n/a

 07-11-2013
>> 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)

Rainer Weikusat
Guest
Posts: n/a

 07-11-2013
Rainer Weikusat <(E-Mail Removed)> 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.

Keith Keller
Guest
Posts: n/a

 07-11-2013
On 2013-07-11, Rainer Weikusat <(E-Mail Removed)> 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

--
http://www.velocityreviews.com/forums/(E-Mail Removed)-francisco.ca.us
(try just my userid to email me)
AOLSFAQ=http://www.therockgarden.ca/aolsfaq.txt
see X- headers for PGP signature information

Jürgen Exner
Guest
Posts: n/a

 07-11-2013
Keith Keller <(E-Mail Removed)-francisco.ca.us> wrote:
>On 2013-07-11, Rainer Weikusat <(E-Mail Removed)> 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