Re: Exporter and subroutine circular dependencies between modules

[email protected] (David Christensen) Sun, 13 Mar 2022 18:43:48 -0700
Newsgroups perl.module-authors
Message-ID <[email protected]>
--------------w3vV0TYMewfxgrQGt04WRwZR
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit

On 3/13/22 15:08, Diab Jerius via module-authors wrote:
> On 3/13/22 16:13, David Christensen wrote:
>> module-authors:
>>
>> I have been wrestling with the Exporter module and subroutine circular 
>> dependencies between modules for a number of years.  I have yet to 
>> find a satisfactory solution.

> If you move import of modules with circular dependencies to runtime 
> rather than compile time:
> 
> 
>     $ diff Exporter-circular-use{.orig,.new}
>     diff Exporter-circular-use.orig/Bar11.pm
>     Exporter-circular-use.new/Bar11.pm
>     13c13,14
>     < use Foo11;
>     ---
>      > require Foo11;
>      > Foo11->import;
>     diff Exporter-circular-use.orig/Foo11.pm
>     Exporter-circular-use.new/Foo11.pm
>     13c13,14
>     < use Bar11;
>     ---
>      > require Bar11;
>      > Bar11->import;
> 
> 
>     $ perl Exporter-circular-use.t
>     ok 1 - foo00
>     ok 2 - foo01
>     ok 3 - foo10
>     ok 4 - foo11
>     1..4


Thank you for the reply.  :-)


Yes, that works.


>   Or move the export completely into compile time:
> 
>     $ diff Exporter-circular-use{.orig,.new}
>     diff Exporter-circular-use.orig/Bar11.pm
>     Exporter-circular-use.new/Bar11.pm
>     9,11c9,11
>     < require Exporter;
>     < our @ISA    = qw( Exporter );
>     < our @EXPORT    = qw( bar );
>     ---
>      > use parent 'Exporter';
>      > our @EXPORT;
>      > BEGIN{ @EXPORT = qw( bar ); }
>     diff Exporter-circular-use.orig/Foo11.pm
>     Exporter-circular-use.new/Foo11.pm
>     9,11c9,11
>     < require Exporter;
>     < our @ISA    = qw( Exporter );
>     < our @EXPORT    = qw( foo );
>     ---
>      > use parent 'Exporter';
>      > our @EXPORT;
>      > BEGIN { @EXPORT = qw( foo ); }


Yes, that also works.  Putting the @EXPORT allocation and initialization 
in a BEGIN block ahead of the 'use parent' looks even better:

2022-03-13 18:15:46 dpchrist@tinkywinky 
~/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ diff Foo11.pm Foo33.pm
1c1
< package Foo11;
---
 > package Foo33;
9,11c9,10
< require Exporter;
< our @ISA	= qw( Exporter );
< our @EXPORT	= qw( foo );
---
 > BEGIN { our @EXPORT = qw( foo ) }
 > use parent 'Exporter';
13c12
< use Bar11;
---
 > use Bar33;


David



2022-03-13 18:38:24 dpchrist@tinkywinky 
~/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ cat /etc/debian_version ; uname -a ; perl -v | head -n 2
9.13
Linux tinkywinky 4.9.0-17-amd64 #1 SMP Debian 4.9.290-1 (2021-12-12) 
x86_64 GNU/Linux

This is perl 5, version 24, subversion 1 (v5.24.1) built for 
x86_64-linux-gnu-thread-multi

2022-03-13 18:40:00 dpchrist@tinkywinky 
~/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ ./Exporter-circular-use.t
ok 1 - foo00
ok 2 - foo01
ok 3 - foo10
Undefined subroutine &Bar11::foo called at Bar11.pm line 22.
not ok 4 - foo11
#   Failed test 'foo11'
#   at ./Exporter-circular-use.t line 24.
#          got: 'main=7
#  foo=6
#   bar=5
# '
#     expected: 'main=7
#  foo=6
#   bar=5
#    foo=4
#     bar=3
#      foo=2
#       bar=1
# '
Undefined subroutine &Bar12::foo called at Bar12.pm line 23.
not ok 5 - foo12
#   Failed test 'foo12'
#   at ./Exporter-circular-use.t line 24.
#          got: 'main=7
#  foo=6
#   bar=5
# '
#     expected: 'main=7
#  foo=6
#   bar=5
#    foo=4
#     bar=3
#      foo=2
#       bar=1
# '
ok 6 - foo21
ok 7 - foo22
ok 8 - foo33
1..8
# Looks like you failed 2 tests of 8.
--------------w3vV0TYMewfxgrQGt04WRwZR
Content-Type: application/gzip;
 name="Exporter-circular-use-20220313-181541.tar.gz"
Content-Disposition: attachment;
 filename="Exporter-circular-use-20220313-181541.tar.gz"
Content-Transfer-Encoding: base64

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

--------------w3vV0TYMewfxgrQGt04WRwZR--