(quickie) (Aliasing) Possible to get this to work in strict?

C

Crom

1: my $n = 5;
2: *r = \$n;
3:
4: $r++; # both should now be 6
5: $n++; # both should not be 7
6:
7: print "\$n = $n\n\$r = $r";


Works fine without 'use strict'...

$n = 7
$r = 7

....but with strict it barfs.

Global symbol "$r" requires explicit package name at line 6.
Global symbol "$r" requires explicit package name at line 9.
 
T

Tassilo v. Parseval

Also sprach Crom:
1: my $n = 5;
2: *r = \$n;
3:
4: $r++; # both should now be 6
5: $n++; # both should not be 7
6:
7: print "\$n = $n\n\$r = $r";


Works fine without 'use strict'...

$n = 7
$r = 7

...but with strict it barfs.

Global symbol "$r" requires explicit package name at line 6.
Global symbol "$r" requires explicit package name at line 9.

You can circumvent that by pre-declaring $r using our() or 'use vars':

use strict;

our $r; # pre-5.6.0 perls: use vars qw/$r/;
my $n = 5;

*r = \$n;
$r++;
print "$n - $r\n";
__END__
6 - 6

Tassilo
 
A

Anno Siegel

Crom said:
1: my $n = 5;
2: *r = \$n;
3:
4: $r++; # both should now be 6
5: $n++; # both should not be 7
6:
7: print "\$n = $n\n\$r = $r";


Works fine without 'use strict'...

$n = 7
$r = 7

...but with strict it barfs.

Global symbol "$r" requires explicit package name at line 6.
Global symbol "$r" requires explicit package name at line 9.

"use strict" means, among other things, that you have to declare
all variables. You haven't declared your variables, so it complains.

Anno
 
M

Michele Dondi

You can circumvent that by pre-declaring $r using our() or 'use vars':

use strict;

our $r; # pre-5.6.0 perls: use vars qw/$r/;
my $n = 5;

*r = \$n;
$r++;
print "$n - $r\n";
__END__
6 - 6

Speaking of which, may I ask you to give an explanation of how this
works internally? (Just curious...)

What I mean is that we all know that Perl5 has basically two
fundamentally orthogonal variable systems. And we know we can access
directly a package's symbol table, but AFAIK we can't do the same with
lexical variables, even though there "MUST" be one, and given the
orthogonality hinted to above, it is somewhat surprising that such an
aliasing can even be done. Oh, and of course on lexical scope exit it
will "downgrade" to a simple copy, won't it? (Just tried, and AFAICT
it is indeed so).

Incidentally Perl6's planned solution to the variables' nature
dichotomy by means of an inner layer of magic, namely that provided by
the MY package, IMHO is very appealing, and I wonder wether it may
eventually leak in some future Perl5 release...


Michele
 
T

Tassilo v. Parseval

Also sprach Michele Dondi:
Speaking of which, may I ask you to give an explanation of how this
works internally? (Just curious...)

It probably means that on the inside just the pointer to the original
variable is copied. On ordinary assignments, perl copies the C structure
into a new variable. Here it just copies the memory address.
What I mean is that we all know that Perl5 has basically two
fundamentally orthogonal variable systems. And we know we can access
directly a package's symbol table, but AFAIK we can't do the same with
lexical variables, even though there "MUST" be one, and given the
orthogonality hinted to above, it is somewhat surprising that such an
aliasing can even be done. Oh, and of course on lexical scope exit it
will "downgrade" to a simple copy, won't it? (Just tried, and AFAICT
it is indeed so).

No, an alias remains an alias. Perl increments the reference-count of
the variable to be aliased:

ethan@ethan:~$ perl -MDevel::peek
{ my $c = 42;
Dump($c);
*alias = \$c;
Dump($alias);
}
Dump($alias);
__END__
SV = IV(0x8163094) at 0x814cc6c
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 42
SV = IV(0x8163094) at 0x814cc6c
REFCNT = 2
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 42
SV = IV(0x8163094) at 0x814cc6c
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 42

So after doing the aliasing, the reference-count has gone up to 2. On
scope exist, it is decreased again by one. Since the reference-count
hasn't yet gone to zero, the memory previously associated with 'my $c'
remains intact and can still be accessed through the alias. Also note
how the memory addresses involved are all identical. My suspicion is
that aliases were just a side-effect that turned out to be very useful.
It is the C-semantics of copying a pointer ported to perl.

Aliases are a lot like hard links on Unices. You can delete the file
that was hard-linked to but the hard link itself remains valid and
behaves if it was the original file. Which it is anyway, from the point
of view of the filesystem.

As for lexical variables, technically they are not very different from
package variables. They have the PADMY flag set which means they are
subject to refcounting. Other than that, they only differ from package
variables in that they are not kept in a symbol-table but in so called
pads. Each block has its own pad and they are inaccessible from
pure-Perl (unless someone writes an XS extension that makes them
accessible).

Tassilo
 
A

Arndt Jonasson

Tassilo v. Parseval said:
As for lexical variables, technically they are not very different from
package variables. They have the PADMY flag set which means they are
subject to refcounting. Other than that, they only differ from package
variables in that they are not kept in a symbol-table but in so called
pads. Each block has its own pad and they are inaccessible from
pure-Perl (unless someone writes an XS extension that makes them
accessible).

Maybe I misunderstand the above, but it seems to say that in the code
snippet below, the lexical variable $x should not be seen by the
'eval' inside the block. But the output in the block is "r = 7" (while
$y is 5, showing that the outer $x is unchanged), so 'eval' does see
the lexical variable. What am I missing?

$e = '$x';
$x = 5;
*y = $x;
{
my $x = 7;
$r = eval $e;
print "r = $r\n";
print "outer r = $y\n";
}
$r = eval $e;
print "r = $r\n";
 
T

Tassilo v. Parseval

Also sprach Arndt Jonasson:
Maybe I misunderstand the above, but it seems to say that in the code
snippet below, the lexical variable $x should not be seen by the
'eval' inside the block. But the output in the block is "r = 7" (while
$y is 5, showing that the outer $x is unchanged), so 'eval' does see
the lexical variable. What am I missing?

Why should 'eval' not see lexical variables? It does see them. It sees
the lexical $x here because inner lexicals override variables by that
name in an outer block.
$e = '$x';
$x = 5;
*y = $x;

Did you mean to write

*y = \$x;

here?
{
my $x = 7;
$r = eval $e;
print "r = $r\n";
print "outer r = $y\n";
}
$r = eval $e;
print "r = $r\n";

With the change suggested above, I get:

r = 7
outer r = 5
r = 5

Is this not what you would expect?

Tassilo
 
A

Arndt Jonasson

Tassilo v. Parseval said:
Also sprach Arndt Jonasson:


Why should 'eval' not see lexical variables? It does see them. It sees
the lexical $x here because inner lexicals override variables by that
name in an outer block.


Did you mean to write

*y = \$x;

here?

Oops, yes. Or *y=*x. I made the last change in the test program but
not in the article.
With the change suggested above, I get:

r = 7
outer r = 5
r = 5

Is this not what you would expect?

It is, but "inaccessible from pure-Perl" made me think it might not
work. Does "inaccessible" simply mean that there is no package hash
table one can traverse to find the variable?
 
A

Anno Siegel

Tassilo v. Parseval said:
Aliases are a lot like hard links on Unices. You can delete the file
that was hard-linked to but the hard link itself remains valid and
behaves if it was the original file. ...

The analogy extends to the link count of a file, which has the same
function and reason-of-being as the refcount of a Perl variable.

Anno
 
M

Michele Dondi

No, an alias remains an alias. Perl increments the reference-count of
the variable to be aliased:

Well, but from the UI-point of view, I mean: it acts in a way that is
perfectly undistinguishable from a copy, doesn't it?
ethan@ethan:~$ perl -MDevel::peek
{ my $c = 42;
Dump($c);
*alias = \$c;
Dump($alias);
}
Dump($alias);
__END__
SV = IV(0x8163094) at 0x814cc6c
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 42
SV = IV(0x8163094) at 0x814cc6c
REFCNT = 2
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 42

I see... but now that I think of it better, examining your example in
detail, isn't it somewhat contradictory that the *package* variable
$alias has the PADMY flag set, what that as you explain below should
mark a lexical variable?


Michele
 
T

Tassilo v. Parseval

Also sprach Michele Dondi:
Well, but from the UI-point of view, I mean: it acts in a way that is
perfectly undistinguishable from a copy, doesn't it?

Yes, quite. There's no way to tell the original from the alias.
I see... but now that I think of it better, examining your example in
detail, isn't it somewhat contradictory that the *package* variable
$alias has the PADMY flag set, what that as you explain below should
mark a lexical variable?

In a way it seems like a contradiction. But on closer inspection it is
not, because you created an alias to a lexical variable. And as there is
no way to distinguish between original and alias (as said above), the
alias must behave just as the original variable. And that includes
refcounting, therefore PADMY.

Tassilo
 
T

Tassilo v. Parseval

Also sprach Tassilo v. Parseval:
Also sprach Michele Dondi:


In a way it seems like a contradiction. But on closer inspection it is
not, because you created an alias to a lexical variable. And as there is
no way to distinguish between original and alias (as said above), the
alias must behave just as the original variable. And that includes
refcounting, therefore PADMY.

When thinking about that a little further, this explanation is
misleading. It implies that perl would internally do additional work to
ensure that both the original and the alias have the same flags. This is
not the case. Perl merely copies the pointer to the original variable
into the alias, and that is the explanation why even a package variable
can have the flags of a lexical. This is easier to understand when
looking at what happens on the C level (simplified):

SV *lexical; /* gets initialized somewhere below */
...
SV *alias = lexical;
SvREFCNT_inc(lexical);

'lexical' and 'alias' point to the same memory address in which all the
flags, slots (such as IV, NV, PV, ...), refcount field etc. are stored.

Tassilo
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
Tassilo v. Parseval
In a way it seems like a contradiction. But on closer inspection it is
not, because you created an alias to a lexical variable. And as there is
no way to distinguish between original and alias (as said above), the
alias must behave just as the original variable. And that includes
refcounting, therefore PADMY.

I do not see what PADMY has to do with refcounting. AFAIK, it is used
(after compilation) for one purpose only: optimization of $a = $b + $c
if $a is lexical; in this case op_add() (sp?) can write to $a directly
instead of writing to a temporary, then copying from a temporary to
$a.

And this is most probably done at compile time only...

Hope this helps,
Ilya
 

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,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top