What does `my' do?!

I

Ilya Zakharevich

I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

Puzzled,
Ilya
 
F

Frank Seitz

Ilya said:
I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

I think, my() creates a variable at compile time but it doesn't
change its value at run time. To achieve the desired effect,
you must initialze $x yourself:

perl -wle 'my $x = 13; BEGIN{ $x=12 } print $x'
13

Frank
 
P

Peter Makholm

Ilya Zakharevich said:
Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

perlsub(1) got the following under the heading 'Private Variables via
my()':

A "my" has both a compile-time and a run-time effect. At
compile time, the compiler takes notice of it. The principal
usefulness of this is to quiet "use strict 'vars'", but it is
also essential for generation of closures as detailed in
perlref. Actual initialization is delayed until run time,
though, so it gets executed at the appropriate time, such as
each time through a loop, for example.

Not that perlsub(1) is the most intuitive place to look for the
documentation for 'my', but at least 'perldoc -f my' referes to it, so
it should be findable.

//Makholm
 
S

sln

I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

Puzzled,
Ilya

perl -wle " BEGIN{ $x=12; print $x; } print 'here'; my $x=99; print $x"
12
here
99
------------
perl -wle " BEGIN{ $x=12; print $x; } print 'here'; my $x; print $x"
12
here
Use of uninitialized value in print at -e line 1.
------------

perl -wle "my $x; undef $x; print $x; BEGIN{ $x=12; } print 'here'; print $x"
Use of uninitialized value in print at -e line 1.

here
Use of uninitialized value in print at -e line 1.
------------

It appears declarations used by and past the BEGIN block is re-initialized
after block execution ('my' is re-examined) while at run-time, assignments
are processed from the beginning.

This makes sense since 'use Module' initializes variables and runs code
at compile time.

But, unusual behavior.

-sln
 
S

sln

I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

Puzzled,
Ilya


perl -wle "BEGIN{ $x=12; } print 'here'; print $x; my $x;"
here
12
---------------
perl -wle "BEGIN{ $x=12; } print 'here'; print $x;"
here
12

Looks like a strange issue. Kind of auto-creates the lexical in the
case of the last one.
 
T

Tim McDaniel

I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

In "man perlsub", under "Private Variables via my()", I see both

The parameter list to my() may be assigned to if desired, which
allows you to initialize your variables. (If no initializer is
given for a particular variable, it is created with the
undefined value.)

and

A "my" has both a compile-time and a run-time effect. At
compile time, the compiler takes notice of it. The principal
usefulness of this is to quiet "use strict 'vars'", but it is
also essential for generation of closures as detailed in
perlref. Actual initialization is delayed until run time,
though, so it gets executed at the appropriate time, such as
each time through a loop, for example.

I think "Actual initialization" refers to explicit assignment via "=",
so if there's no initialization, there's no run-time assignment.
So I think
(If no initializer is given for a particular variable, it is
created with the undefined value.)
is inaccurate: it's always created undef.

So I'm thinking the the sequence is:
- compile time:
= variable is created
= since it has to have SOME value in Perl, it's set to undef
- run time:
= if an explicit initializer is provided, the assignment is done
= so if no explicit initializer is provided, it is unchanged

That is, that
my $y = 123;
is equivalent to
my $y; BEGIN { undef $y; }
$y = 123; # assigned at run time
$y;
and
my $z;
is
my $z; BEGIN { undef $z; }
$z;

That seems consistent with the examples and with
perl -wle 'my $x = 13; BEGIN{ print "in begin ", $x; $x=12 } print $x'
Use of uninitialized value $x in print at -e line 1.
in begin
^ both showing that it's created undef
13
 
T

Tad J McClellan

Ilya Zakharevich said:
I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12


You develop on Windows?

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why?


Because $x is not being assigned to in the my(), I guess.

i.e. "no initializer is given" (see below).

Is it documented?


I think so, if you can divine that "created" means "at compile time"...

From perlsub.pod (with my emphasis):

The parameter list to my() may be assigned to if desired, which allows you
to initialize your variables. (If no initializer is given for a
particular variable, it is created with the undefined value.)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

and since "creation" is in my()'s compile-time component, that is when
it is given the undef value.

If we _do_ give an initializer:

perl -wle 'my $x=undef; BEGIN{ $x=12 } print $x'

then things match up with your expectations.
 
T

Tad J McClellan

[ snip all but "the last one" ]
---------------
perl -wle "BEGIN{ $x=12; } print 'here'; print $x;"
here
12

Looks like a strange issue. Kind of auto-creates the lexical in the
case of the last one.


There is no lexical in that one. There are only package variables there.
 
S

sln

Ilya Zakharevich said:
I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12


You develop on Windows?

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why?


Because $x is not being assigned to in the my(), I guess.

i.e. "no initializer is given" (see below).

Is it documented?


I think so, if you can divine that "created" means "at compile time"...

From perlsub.pod (with my emphasis):

The parameter list to my() may be assigned to if desired, which allows you
to initialize your variables. (If no initializer is given for a
particular variable, it is created with the undefined value.)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

and since "creation" is in my()'s compile-time component, that is when
it is given the undef value.

If we _do_ give an initializer:

perl -wle 'my $x=undef; BEGIN{ $x=12 } print $x'

then things match up with your expectations.
^^^^^
Not really...

perl -wle "my $x=undef; BEGIN{ $x=12 } print $x"
12
 
I

Ilya Zakharevich

perl -wle " BEGIN{ $x=12; print $x; } print 'here'; my $x=99; print $x"
12
here
99
------------
perl -wle " BEGIN{ $x=12; print $x; } print 'here'; my $x; print $x"
12
here
Use of uninitialized value in print at -e line 1.

Keep in mind that in these examples you have DIFFERENT variables, all
named $x.

Yours,
Ilya
 
I

Ilya Zakharevich

what you expect is exactly what happens. OK, let's see what's in
pp_hot.c... it appears that 'my' actually clears the variable on scope
*exit*, not when the 'my' is encountered at runtime, and this has been
there since at least 5.000. I suppose it makes sense: since we must
clear the variable on scope exit (to get timely destruction), there's no
point clearing it on scope entry as well.

Thanks a lot. This is an explanation which is "almost correct" (see
below), and may be reasonably expected to be understood even by people
who do not read Perl source... In other words, it makes sense to
document this...

====

Why it is not completely correct:

perl -wle "eval shift; delayed()" "my $x; $x=12; sub delayed {print $x}"
12

*After* `eval' is executed, the scope of $ARGV[0] is exited. But as
you see (and this is *very expected*), $x is not cleared on scope
exit.

I think it might have been even myself who implemented (one of the
facets of) this behaviour. The more complete explanation should be
more similar to:

if refcount of lexical variable is 1, it is cleared on exit;

otherwise it is marked in some way, and it is cleared on entry...

I'm kinda fuzzy on details...

Thanks again,
Ilya
 
I

Ilya Zakharevich

perlsub(1) got the following under the heading 'Private Variables via
my()':

A "my" has both a compile-time and a run-time effect. At
compile time, the compiler takes notice of it. The principal
usefulness of this is to quiet "use strict 'vars'", but it is
also essential for generation of closures as detailed in
perlref. Actual initialization is delayed until run time, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
though, so it gets executed at the appropriate time, such as
each time through a loop, for example.

Not that perlsub(1) is the most intuitive place to look for the
documentation for 'my', but at least 'perldoc -f my' referes to it, so
it should be findable.

Now, if you look AGAIN at what I wrote, you see that this explanation
is not correct.

(Likewise for many other replies from people who forget how `my $foo'
behaves in a loop.)

Yours,
Ilya
 
F

Frank Seitz

Ilya said:
Now, if you look AGAIN at what I wrote, you see that this explanation
is not correct.

I think it is correct. Initialization means assignment.
You didn't assign a value in your code.

Frank
 
E

Eric Pozharski

I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

Fairly strange shell you have. Or this is a violation of
copy-paste-but-retype rule.

I've come to conclusion that either everyone just translated seemlesly
double-quotes in single-quotes (while retyping) or everyone are that
afraid of you that just prefered to skip that. How you've managed them
into that fear?

*CUT*
 
T

Tad J McClellan

Eric Pozharski said:
Fairly strange shell you have.


That's what I thought too.

Not actually that the shell was strange, but that it was strange
for a programmer of Ilya's cluefulness to be using Windows (which
was my erroneous guess as to why it was double quoted).

I asked him, and he explained else-thread.

everyone are that
afraid of you that just prefered to skip that. How you've managed them
into that fear?


I am fearless!

I am unmanageable! (and so is my hair)
 
I

Ilya Zakharevich

I think it is correct. Initialization means assignment.

No, it does not. And I believe you may be, in general, confused on
what this is about...

Thanks anyway,
Ilya
 
T

Tim McDaniel

"Ilya Zakharevich":
I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

I think there is confusion about the term "executed" in conjunction with
"my". You have a misunderstanding of how the run-time part of "my" is
implemented.

The run-time effect of "my" is that it marks the variable to be
cleared at the end of the current scope. That's all.

To clarify, "that's all" in this example. The other run-time effect
of "my" is that, if there be an initial value supplied (for example,
on the right-hand side of "="), this assignment would be done at run
time. (Ilya was expecting that, if there be no right-hand side, it
would be set to undef, which is apparently not so.)
 
T

Tim McDaniel

Quoth (e-mail address removed):
"Ilya Zakharevich":

I managed to confuse myself in a teaspoon... Consider

perl -wle "my $x; BEGIN{ $x=12 } print $x"
12

I would expect it to warn that $x is uninitialized, and print
nothing. The reasoning goes like that:

AT COMPILE TIME:
`my' is seen; after this $x is considered as lexical
BEGIN is compiled and executed; $x becomes 12
`print' is compiled

AT RUN TIME
`my' is executed. [*] Variable $x becomes undef
`print' is executed

Apparently, [*]-action is not executed in this context. The question
is: why? Is it documented?

I think there is confusion about the term "executed" in conjunction with
"my". You have a misunderstanding of how the run-time part of "my" is
implemented.

The run-time effect of "my" is that it marks the variable to be
cleared at the end of the current scope. That's all.

To clarify, "that's all" in this example. The other run-time effect
of "my" is that, if there be an initial value supplied (for example,
on the right-hand side of "="), this assignment would be done at run
time. (Ilya was expecting that, if there be no right-hand side, it
would be set to undef, which is apparently not so.)

What? No. Perl is not C, and doesn't have a concept of
'initialization' distinct from ordinary assignment. Any assignment to
a newly created lexical is executed when control flow reaches that
point at runtime, just as with any other expression.

We appear to be in vehement agreement: anything that looks like
"initialization" in a "my" is not special, but is merely a standard
run-time assignment like any other. (My use of "initial value" may
have been inapt, especially in this example, where it's assigned in
the BEGIN block.)
 
S

sln

Keep in mind that in these examples you have DIFFERENT variables, all
named $x.

Yours,
Ilya

Yes, one is $main::x in the BEGIN, the other is lexical my().
Didn't realize until after I posted.

Besides this unusual initialization/assignment thing, the docs specify
BEGIN is wrapped in an eval when it is run, which I thought odd.

Hope you fix it.

-sln
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top