'my' doesn't totally isolate

J

John Brock

I seem to have misunderstood something about 'my'. I was under
the impression that when you defined a variable in a function or
block using 'my' the variable was totally private and totally
isolated from anything that happens anywhere else. In particular
I thought that unless I explicitly gave the variable a value it
would start out undefined every time the function or block was
called. But in fact this does not seem to be the case, as the
following script illustrates:

=== Begin script ===
sub zzz {
my @aaa;

print "defined: '", defined(@aaa), "', last: $#aaa\n";

@aaa = (1, 2, 3);
}

zzz();
zzz();
=== End script ===

I would have expected that both calls to zzz() would produce exactly
the same output. But in fact what I get, using Perl 5.8.0 under
Solaris, is:

=== Begin output ===
defined: '', last: -1
defined: '1', last: -1
=== End output ===

In the first invocation of zzz() array @aaa start out undefined,
while in the second @aaa starts out as a defined array with length
0. This is not what I expected at all! I haven't been able to
find this behavior written up anywhere, so is it possible it is a
bug? If not, can anyone explain what is happening, or point me to
an explanation?
 
G

Gunnar Hjalmarsson

John said:
I seem to have misunderstood something about 'my'.

You have rather misunderstood something about the defined() function.

perldoc -f defined
 
P

Paul Lalli

I seem to have misunderstood something about 'my'. I was under
the impression that when you defined a variable in a function or
block using 'my' the variable was totally private and totally
isolated from anything that happens anywhere else. In particular
I thought that unless I explicitly gave the variable a value it
would start out undefined every time the function or block was
called. But in fact this does not seem to be the case, as the
following script illustrates:

=== Begin script ===
sub zzz {
my @aaa;

print "defined: '", defined(@aaa), "', last: $#aaa\n";

@aaa = (1, 2, 3);
}

zzz();
zzz();
=== End script ===

I would have expected that both calls to zzz() would produce exactly
the same output. But in fact what I get, using Perl 5.8.0 under
Solaris, is:

=== Begin output ===
defined: '', last: -1
defined: '1', last: -1
=== End output ===

perldoc -f defined:
Use of "defined" on aggregates (hashes and arrays)
is deprecated. It used to report whether memory for
that aggregate has ever been allocated. This
behavior may disappear in future versions of Perl.
You should instead use a simple test for size:

Paul Lalli
 
J

John Brock

You have rather misunderstood something about the defined() function.

perldoc -f defined

Hmmm.... So how am I supposed to distinguish between an array
which has not been assigned to and one whose length just happens
to be zero?

Also, I can still get the behavior I expected by using undef() on
the array in question after I define it with 'my', but I am not
sure why this works if undefined() simply tells me whether memory
for the array has *ever* been allocated. Can I trust this behavior?
 
J

John Brock

Purl Gurl said:
sub zzz
{
my @aaa;
print "defined: '", defined(@aaa), "', last: $#aaa\n";
}
zzz();
zzz();

----

sub zzz
{
my @aaa;
print "defined: '", defined(@aaa), "', last: $#aaa\n";
my @aaa = qw (1 2 3);
}
zzz();
zzz();


Run those two examples and note results.

Noted, but I don't understand what is being demonstrated. For one
thing, I never define a variable with 'my' twice in the same block;
is there a reason I might want to?

But aside from that, I see that assigning a value to @aaa using
'my' causes @aaa to behave as I had expected in the second call to
zzz(). But I don't understand why, or how this helps me do what
I am trying to do (which is to flag the first use of an array inside
a function).
 
R

Randal L. Schwartz

John> Hmmm.... So how am I supposed to distinguish between an array
John> which has not been assigned to and one whose length just happens
John> to be zero?

You don't. The difference between the two is (ahem) undefined. :)

defined() on aggregates is deliberately undefined, because it depends
on allocation strategies. You want to slow down *all* of Perl just
to get something you should figure out from context instead?

print "Just another Perl hacker,"
 
J

John Brock

John> Hmmm.... So how am I supposed to distinguish between an array
John> which has not been assigned to and one whose length just happens
John> to be zero?

You don't. The difference between the two is (ahem) undefined. :)

defined() on aggregates is deliberately undefined, because it depends
on allocation strategies. You want to slow down *all* of Perl just
to get something you should figure out from context instead?

Well, I thought I *was* figuring it out from context. I thought
Perl had a nice little feature where I could tuck some extra
information into one variable rather than defining two. But if it
doesn't work that way then it doesn't work that way.

I guess that means I can't even trust that defined(@aaa) will always
return FALSE if I call it after calling undef(@aaa) (even though
that seems to work for me right now). Bummer!
 
U

Uri Guttman

JB> Hmmm.... So how am I supposed to distinguish between an array
JB> which has not been assigned to and one whose length just happens
JB> to be zero?

why should you care? do you have a valid reason?

JB> Also, I can still get the behavior I expected by using undef() on
JB> the array in question after I define it with 'my', but I am not
JB> sure why this works if undefined() simply tells me whether memory
JB> for the array has *ever* been allocated. Can I trust this behavior?

undef on aggregates is also something you don't want. it will free the
allocated ram and it also leads coders (like you) to think that defined
has meaning on aggregates. you clear arrays and hashes by assigning an
empty list () to them. my by itself will always create an empty array or
hash as that is its runtime effect.

uri
 
U

Uri Guttman

John> Hmmm.... So how am I supposed to distinguish between an array
John> which has not been assigned to and one whose length just happens
John> to be zero?
JB> Well, I thought I *was* figuring it out from context. I thought
JB> Perl had a nice little feature where I could tuck some extra
JB> information into one variable rather than defining two. But if it
JB> doesn't work that way then it doesn't work that way.

JB> I guess that means I can't even trust that defined(@aaa) will always
JB> return FALSE if I call it after calling undef(@aaa) (even though
JB> that seems to work for me right now). Bummer!

you are not making much sense here. why should you care if an array was
allocated or not? it is not a useful boolean as you have little control
over it. what control you see is an undocumented side effect and may go
away.

now state your real problem and stop worrying about array storage
allocation and undef. it is a red herring and you should drop it now.

uri
 
J

John Brock

Uri Guttman said:
you are not making much sense here. why should you care if an array was
allocated or not? it is not a useful boolean as you have little control
over it. what control you see is an undocumented side effect and may go
away.

If would be a useful boolean if I did have control over it. What
I've learned here is that I don't. Too bad. Live and learn.
now state your real problem and stop worrying about array storage
allocation and undef. it is a red herring and you should drop it now.

Calm down! My real problem was perfectly right clear from my first
post. I didn't properly understand a feature of the language. I
understand it better now, so my purpose in coming here has been
accomplished.
 
U

Uri Guttman

JB> In article <[email protected]>,

JB> If would be a useful boolean if I did have control over it. What
JB> I've learned here is that I don't. Too bad. Live and learn.

you still haven't explained a real use for this. i reread your OP and it
just bitches about undef and defined and such without stating a REASON
for needing this boolean.

JB> Calm down! My real problem was perfectly right clear from my first
JB> post. I didn't properly understand a feature of the language. I
JB> understand it better now, so my purpose in coming here has been
JB> accomplished.

but your original need for this feature is still unknown. you are having
what is called an XY problem. your real problem is X but you think the
problem is Y and you ask how to solve Y.

uri
 
C

ctcgag

Hmmm.... So how am I supposed to distinguish between an array
which has not been assigned to and one whose length just happens
to be zero?

How am I supposed to distinguish between an array that never held elements
summing up to 19856, versus an array that used to, but now doesn't, hold
elements that summed to 19856?

Perhaps if you can explain what you are trying to accomplish through
making this distinction, we could suggest a better way to accomplish it.
Also, I can still get the behavior I expected by using undef() on
the array in question after I define it with 'my', but I am not
sure why this works if undefined() simply tells me whether memory
for the array has *ever* been allocated. Can I trust this behavior?

No. If you want to have a status variable, make an explicit one.

Xho
 
C

ctcgag

If would be a useful boolean if I did have control over it. What
I've learned here is that I don't. Too bad. Live and learn.

You could always use references. Then you can distinguish an undefined
scalar versus a scalar with reference to an empty array. This leads to
very intricate code with hard to find bugs, but if the fundamental problem
is very intricate with subtle logic traps, then that is just the nature of
the beast.

Xho
 
J

John Brock

Uri Guttman wrote:
I don't think the OP had a "real use" for this. I think he was just
exploring the nuances of the language and came across something that
behaved differently than he expected it to.

Actually I did have a real and perfectly sensible reason for testing
an array using defined(), but when I realized that defined() didn't
do what I thought it did I solved the problem another way, using
an additional flag variable. I did get some very helpful responses
here, but I have to say I didn't appreciate the demands that I
explain my need for this feature. No Mr. Guttman, I was not having
an "XY problem". I didn't bother explaining my need for the feature
because the code I was using it in was trivial, the fix was trivial,
and neither was worth posting. My concern was understanding. I
have been coding Perl for a long time, and it bothered me that
defined() wasn't working the way I thought it should. Randal
Schwartz pretty much cleared it up for me: for performance reasons
defined() is not defined for aggregates.

Okay. However while the 3rd edition of Programming Perl does say
that the use of defined() on aggregates is "deprecated", when I go
back to the *2nd* edition I am explicitly told it is okay. (pp.
155: "You may also check to see whether arrays, hashes, or subroutines
exist."). Clearly this is where I got the idea that doing this
was kosher, and I have to say I am a bit ticked off about it, since
I know I have done this elsewhere (although under this is the first
time it has caused a problem). So, did the behavior of Perl change
at some point, or was the documentation changed because someone
noticed that the behavior was unreliable?

And I am still interested in learning whether

my @aaa;
undef(@aaa);
...
defined(@aaa);

will always return FALSE, which would mean that I could still use
the test as a flag. In my code it does, but if defined(@aaa) is
truly "undefined" then I guess I shouldn't count on it.
 
A

Anno Siegel

John Brock said:
Actually I did have a real and perfectly sensible reason for testing
an array using defined(), but when I realized that defined() didn't
do what I thought it did I solved the problem another way, using
an additional flag variable. I did get some very helpful responses
here, but I have to say I didn't appreciate the demands that I
explain my need for this feature.

So we're supposed to answer your questions, but not ask questions
back? I don't think you quite understand how this Usenet thing works.
No Mr. Guttman, I was not having
an "XY problem".

Problem X: I want to associate a "pristine" state with an aggregate.
Non-solution Y: use defined() on the aggregate. Your original question
was entirely about Y, no mention of X. That is what we call an XY
problem here.
I didn't bother explaining my need for the feature
because the code I was using it in was trivial, the fix was trivial,
and neither was worth posting.

Trivial or not, if you keep parts of the problem to yourself, expect
questions.
My concern was understanding. I
have been coding Perl for a long time, and it bothered me that
defined() wasn't working the way I thought it should. Randal
Schwartz pretty much cleared it up for me: for performance reasons
defined() is not defined for aggregates.

Okay. However while the 3rd edition of Programming Perl does say
that the use of defined() on aggregates is "deprecated", when I go
back to the *2nd* edition I am explicitly told it is okay. (pp.
155: "You may also check to see whether arrays, hashes, or subroutines
exist."). Clearly this is where I got the idea that doing this
was kosher, and I have to say I am a bit ticked off about it, since
I know I have done this elsewhere (although under this is the first
time it has caused a problem).

You are ticked off easily.

Perl is a fast-moving target, and printed documentation is bound to
be out of date at some time. Use the online documentation that
comes with your version of Perl. "perldoc -f defined".
So, did the behavior of Perl change
at some point, or was the documentation changed because someone
noticed that the behavior was unreliable?

AFAIK the change happened with Perl 5 when lexicals were introduced.
Whether the introduction of lexicals was the reason for the change,
I don't know, but I suspect so.
And I am still interested in learning whether

my @aaa;
undef(@aaa);
...
defined(@aaa);

will always return FALSE, which would mean that I could still use
the test as a flag. In my code it does, but if defined(@aaa) is
truly "undefined" then I guess I shouldn't count on it.

"defined(@aaa)" is deprecated, unreliable, non-portable and subject
to change without notice. Okay? Okay.

Anno
 

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
474,158
Messages
2,570,882
Members
47,414
Latest member
djangoframe

Latest Threads

Top