C.DeRykus said:
Rainer Weikusat <
[email protected]> writes:
[...]
When building state machines in C, I usually use a function pointer
as 'state variable' because this implies there's no need to
explicitly written, state-dependent control transfer code. The
first time I did this in Perl, it occurred to me that it should be
possible to simplify the 'obvious' implementation,using a
module-global scalar variable holding a reference to the
subroutine to be executed next, to one which just invokes the
subroutine by name
[...]
------------
package FlipFlop;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(v);
-----
qw(*v); # <----------
Ran into this by accident. Exporting the actual glob
makes your flipflop work:
our @EXPORT = qw( *v );
$ perl -MFlipFlop -le 'while(1) { print v();sleep 1}'
0
1
...
Here's the relevant bit from perlmod:
What makes all of this important is that the
Exporter module uses glob aliasing as the import/
export mechanism. Whether or not you can properly
localize a variable that has been exported from a
module depends on how it was exported:
@EXPORT = qw($FOO); # Usual form, can't be
# localized
@EXPORT = qw(*FOO); # Can be localized
[...]
So, evidently, Perl has to be able localize the
glob... to do the glob twiddle on the fly.
This is going to become somewhat lengthy ...
What the text you quoted refers to as 'can be localized' is another
side effect of the glob export. I think I should first show the
difference between this "can't be localized" and "can be
localized". Assuming that a file named Localized.pm with the following
content
-----------
package Localized;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw($a_var a_sub);
our $a_var = 3;
sub a_sub {
return $a_var + 1;
}
1;
------------
is available in the perl module search path, the program included
below
------------
use Localized;
print a_sub(), "\n";
{
local $a_var = 55;
print a_sub(), ' ', $a_var, "\n";
}
------------
will print
,----
| 4
| 4 55
`----
The reason for this can be seen by modifying it as follows:
------------
use Devel:
eek;
use Localized;
Dump(*a_var);
Dump(*Localized::a_var);
{
local $a_var = 55;
Dump(*a_var);
}
------------
The output of that is
,----
| SV = PVGV(0x6a3740) at 0x68b558
| REFCNT = 4
| FLAGS = (MULTI,IN_PAD,IMPORT( SV ))
| NAME = "a_var"
| NAMELEN = 5
| GvSTASH = 0x605bb0 "main"
| GP = 0x68e320
| SV = 0x660390
| REFCNT = 1
| IO = 0x0
| FORM = 0x0
| AV = 0x0
| HV = 0x0
| CV = 0x0
| CVGEN = 0x0
| LINE = 193
| FILE = "/usr/share/perl/5.10/Exporter/Heavy.pm"
| FLAGS = 0x1a
| EGV = 0x68b558 "a_var"
| SV = PVGV(0x65b490) at 0x660378
| REFCNT = 3
| FLAGS = (MULTI,IN_PAD)
| NAME = "a_var"
| NAMELEN = 5
| GvSTASH = 0x63cfa8 "Localized"
| GP = 0x62f1d0
| SV = 0x660390
| REFCNT = 1
| IO = 0x0
| FORM = 0x0
| AV = 0x0
| HV = 0x0
| CV = 0x0
| CVGEN = 0x0
| LINE = 8
| FILE = "Localized.pm"
| FLAGS = 0xa
| EGV = 0x660378 "a_var"
| SV = PVGV(0x6a3740) at 0x68b558
| REFCNT = 5
| FLAGS = (MULTI,IN_PAD,IMPORT( SV ))
| NAME = "a_var"
| NAMELEN = 5
| GvSTASH = 0x605bb0 "main"
| GP = 0x68e320
| SV = 0x605d48
| REFCNT = 1
| IO = 0x0
| FORM = 0x0
| AV = 0x0
| HV = 0x0
| CV = 0x0
| CVGEN = 0x0
| LINE = 193
| FILE = "/usr/share/perl/5.10/Exporter/Heavy.pm"
| FLAGS = 0x1a
| EGV = 0x68b558 "a_var"
`----
After the initial import, the GPs of both a_var point to different
objects but the SV slot of each GP points to the same scalar. The
later local changes the binding of the SV slot of the a_var GP in main
but doesn't affect the SV slot of Localized::a_var. When the *a_var
glob is exported instead, this changes to
,----
| SV = PVGV(0x6a3740) at 0x660258
| REFCNT = 4
| FLAGS = (MULTI,IN_PAD,IMPORTALL)
| NAME = "a_var"
| NAMELEN = 5
| GvSTASH = 0x605bb0 "main"
| GP = 0x62f1d0
| SV = 0x660390
| REFCNT = 2
| IO = 0x0
| FORM = 0x0
| AV = 0x0
| HV = 0x0
| CV = 0x0
| CVGEN = 0x0
| LINE = 8
| FILE = "Localized.pm"
| FLAGS = 0xfa
| EGV = 0x660378 "a_var"
| SV = PVGV(0x65b490) at 0x660378
| REFCNT = 3
| FLAGS = (MULTI,IN_PAD)
| NAME = "a_var"
| NAMELEN = 5
| GvSTASH = 0x63cfa8 "Localized"
| GP = 0x62f1d0
| SV = 0x660390
| REFCNT = 2
| IO = 0x0
| FORM = 0x0
| AV = 0x0
| HV = 0x0
| CV = 0x0
| CVGEN = 0x0
| LINE = 8
| FILE = "Localized.pm"
| FLAGS = 0xa
| EGV = 0x660378 "a_var"
| SV = PVGV(0x6a3740) at 0x660258
| REFCNT = 5
| FLAGS = (MULTI,IN_PAD,IMPORTALL)
| NAME = "a_var"
| NAMELEN = 5
| GvSTASH = 0x605bb0 "main"
| GP = 0x62f1d0
| SV = 0x605d48
| REFCNT = 2
| IO = 0x0
| FORM = 0x0
| AV = 0x0
| HV = 0x0
| CV = 0x0
| CVGEN = 0x0
| LINE = 8
| FILE = "Localized.pm"
| FLAGS = 0xfa
| EGV = 0x660378 "a_var"
`----
Here, the GP associated with both names is identical and rebinding the
SV slot of this GP thus causes a change visible to the a_sub
subroutine. With this change, the output of the original program
becomes
,----
| 4
| 56 55
`----
This 'GP' export is also what causes the subroutine switching in the
FlipFlop example to work as intended: Since both FlipFlop::v and
main::v share a GP, changing the CV slot of this GP in FlipFlop is
also visible in main. The downsides of this for a pure subroutine
export/ import are that changes in the importing module may now effect
changes in the exporting module, as demonstrated in the a_var example,
which is not exactly obvious and usually not intended, and that this
still doesn't guarantee that modifications to the FlipFlop symbol
table will remain visible in main: This only works for as long as both
continue to share the GP and it is possible to cause a new GP to be
assigned to either v, eg, by assigning a different glob to *v.