### Tell me how it works!

by nagalenoj (Friar)
 on Jan 28, 2009 at 14:44 UTC Need Help??
nagalenoj has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

I expected the code will print nothing. But, it's not.

\$a = 10; @a = qw(1 2 3); *b=*a; undef *a; print @b;

How this prints the output as 1 2 3?

Replies are listed 'Best First'.
Re: Tell me how it works!
by ikegami (Pope) on Jan 28, 2009 at 16:14 UTC

undef(@a) would give you want you want. undef isn't recursive. Undefining the glob doesn't undefine the values referenced by the glob.

Before glob assignment ---------------------- *main::a *main::b | | | +-------+ +-------+ | +--> | Glob | | Glob | <--+ +-------+ +-------+ +-------+ +-------+ | GP ----> | GP | | GP | <---- GP | +-------+ +-------+ +-------+ +-------+ +-- ARRAY | | ARRAY --+ +-------+ | +-------+ +-------+ | | Array | <-+ +-> NULL +-------+ | 1,2,3 | +-------+ After glob assignment --------------------- *main::a *main::b | | | +-------+ +-------+ | +--> | Glob | | Glob | <--+ +-------+ +--------+ +-------+ | GP ---------> | GP | <--------- GP | +-------+ +--------+ +-------+ | ARRAY --+ +--------+ | +-------+ +-> | Array | +-------+ | 1,2,3 | +-------+ After "undef *a" (Gets a fresh GP, undoing the glob assignment) ----------------- *main::a *main::b | | | +-------+ +-------+ | +--> | Glob | | Glob | <--+ +-------+ +-------+ +-------+ +-------+ | GP ----> | GP | | GP | <---- GP | +-------+ +-------+ +-------+ +-------+ +-- ARRAY | | ARRAY --+ | +-------+ +-------+ | +-------+ NULL <-+ +-> | Array | +-------+ | 1,2,3 | +-------+ If you had done "undef @a" (Clears @a) -------------------------- *main::a *main::b | | | +-------+ +-------+ | +--> | Glob | | Glob | <--+ +-------+ +--------+ +-------+ | GP ---------> | GP | <--------- GP | +-------+ +--------+ +-------+ | ARRAY --+ +--------+ | +-------+ +-> | Array | +-------+ | () | +-------+

Note that "@a=();" is usually better than "undef @a;" since it doesn't discard @a's buffer.

Did you create the ascii art yourself? Seems like that would be extremely tedious to do.

And you didn't even know bears could type.

Yes to both.
Re: Tell me how it works!
by zentara (Archbishop) on Jan 28, 2009 at 14:58 UTC
Since no one else mentioned it, as a habit, avoid using \$a and \$b as variables....they are used in the sort function, and will cause trouble if you sort anywhere in your script.

I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: Tell me how it works!
by citromatik (Curate) on Jan 28, 2009 at 15:31 UTC

Because undef *a undefines the typeglob *a, but not the underlying slots. Look at these 2 examples:

#1 \$a = 10; *b = *a; \$a = 4; print \$b; # <- prints 4 #2 \$a = 10; *b = *a; undef *a; \$a = 4; print \$b; # <- prints 10!

citromatik

Re: Tell me how it works!
by gone2015 (Deacon) on Jan 28, 2009 at 14:49 UTC

Because *a is implicitly a collection of pointers to the various \$a, @a, etc values. So *b = *a copies those pointers, and undef *a wipes out the original collection of pointers, but not the copy.

Update: my apologies, I omitted one level of indirection. I am grateful to brother citromatik for pointing out the error of my ways. (I will now go and mediate on the problem of hubris.)

Correcting my earlier explanation... What is happening is that *a implicitly refers to a structure which contains a collection of pointers to the various \$a, @a, etc values. So *b = *a makes *b implicitly refer to the same structure as *a. The operation undef *a wipes out the implicit reference -- it does not affect *b, or the structure, or the values pointed to by that structure.

So *b = *a copies those pointers, and undef *a wipes out the original collection of pointers, but not the copy.

That is not true, typeglob assignment performs an aliasing operation:

\$x = 10; @x = qw(1 2 3); *y = *x; \$x = 12; print \$y; # <- Prints 12 undef \$x; print \$y; # <- Warns "Use of uninitialized value in..."

See perlmod

citromatik

*a=*b;

But, I read somewhere that assigning the typeglob(*a) will make both to point the same location(address/ memory).

So, When I undef the *a, how the *b remains the same?

Can you clear me in this?

Re: Tell me how it works!
by jethro (Monsignor) on Jan 28, 2009 at 14:49 UTC
From the camel-book:
Use only on a scalar value, an entire array or hash, or a subroutine n +ame. ... The undef function will probably not do what you expect on most specia +l variables

Hmmm... That is not what the documentation says (at least for versions 5.10 and 5.8.8)

undef - Undefines the value of EXPR, which must be an lvalue. Use only on a scalar value, an array (using "@"), a hash (using "%"), a subroutine (using "&"), or a typeglob (using "*")

citromatik

Re: Tell me how it works!
by Bloodnok (Vicar) on Jan 28, 2009 at 17:14 UTC
When seeking advice &/or instruction, it's considerably more polite to ask (rather than instruct) e.g. Please tell me how this works, Can anyone explain this ? etc.

A user level that continues to overstate my experience :-))
Re: Tell me how it works!
by Marshall (Abbot) on Jan 28, 2009 at 17:47 UTC
Very wise Monks have covered the "how". I am curious as to the "why"?. What is the purpose and the real world application?
Why what? Why create an alias?
sub inplace_uc { our \$text; local *text = \\$_[0]; \$text =~ tr/a-z/A-Z/; }

I was enquiring as to what the orginal poster wanted to accomplish and why he thought he needed the typeglob syntax. That's a different question than how it works. You definately know how it works. We have a great intellectual question, but maybe we should be answering a different question? I'm just probing a bit to see if there is some more fundamental application issue here.

I looked at this inplace_uc code and I did add "\$text =~" in front of the tr, which seemed appropriate.

Here, there is really no performance to be gained that I can see. The inplace_uc() call passes the whole string on the stack and there is some stuff to get the address of it. If we are doing an "inplace" replacement, why not just pass the addresss of the string instead of the whole string? My inplace_uc2() uses the address of the string in a very straightforward way.

As a perfence of style, I would always expect an inplace modification to to take place on an address or in Perl lingo a referece to something. Ok, mileage varies as they say.

#!/usr/bin/perl -w use strict; my \$lc_msg = 'message'; inplace_uc (\$lc_msg); print "\$lc_msg\n"; sub inplace_uc { our \$text; local *text = \\$_[0]; # equivalent to: # local *text = \shift; \$text =~ tr/a-z/A-Z/; # added \$text =~ } my \$lc_msg_y = 'another_message'; inplace_uc2 (\\$lc_msg_y); print "\$lc_msg_y\n"; sub inplace_uc2 { my \$str_ref = shift; \$\$str_ref =~ tr/a-z/A-Z/; } # prints: #MESSAGE #ANOTHER_MESSAGE

Create A New User
Node Status?
node history
Node Type: perlquestion [id://739586]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
 [choroba]: Any Monks online that can check what went wrong? [Copacetic]: Sorry, I've just discovered that it gives a useful error message if I select "preview" (as well as removing the "create" button for some reason). It was that my title wasn't long enough. Thanks for your help. [choroba]: :-)

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (10)
As of 2017-05-26 15:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My favorite model of computation is ...

Results (190 votes). Check out past polls.