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.


To explain the problem: assume I have a module Foo that contains a subroutine foo(), a module Bar that contains a subroutine bar(), foo() calls bar(), and bar() calls foo(). I can write a script that calls foo() and the code will compile and run if either Foo or Bar do not employ Exporter, but the code will fail at compile or runtime if both Foo and Bar employ Exporter. Code that demonstrates failure at runtime is attached. A sample run follows.


"Don't do circular dependencies" was the first thought that came to mind, but myself and others have encountered compelling use-cases -- DRY, debug dumping, testing, higher-order programming, etc..


My first work-around was to put all interdependent subroutines into one module. This became unwieldy as the number of inter-dependent subroutines grew.


My second work-around was to group subroutines by dependency level and to place each group into a module. This damages conceptual integrity, the accounting is tedious and error prone, and architectural changes that cause a subroutine to change levels can result in O(n**2) effort.


More recently, I have been experimenting with putting one or a few subroutines into a source file and assembling Perl modules and scripts via #include statements and the C preprocessor via a hacked Filter::cpp:

https://github.com/rurban/Filter/issues/15

The alpha code is limited and brittle. I don't know if the idea, if taken further, would lead to a generally useful solution.


What is the "proper" way to avoid or solve the problem of subroutine circular dependencies between modules?


David



2022-03-13 11:52:17 dpchrist@tinkywinky ~/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ cat /etc/debian_version
9.13

2022-03-13 11:52:27 dpchrist@tinkywinky ~/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ uname -a
Linux tinkywinky 4.9.0-17-amd64 #1 SMP Debian 4.9.290-1 (2021-12-12) x86_64 GNU/Linux

2022-03-13 11:52:29 dpchrist@tinkywinky ~/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ perl -v | head -n 2

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

2022-03-13 11:52:33 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
# '
1..4
# Looks like you failed 1 test of 4.



2022-03-13 11:54:39 dpchrist@samba /var/local/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ freebsd-version
12.3-RELEASE-p2

2022-03-13 11:54:43 dpchrist@samba /var/local/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ uname -a
FreeBSD samba.tracy.holgerdanske.com 12.3-RELEASE-p1 FreeBSD 12.3-RELEASE-p1 GENERIC amd64

2022-03-13 11:54:45 dpchrist@samba /var/local/samba/dpchrist/sandbox/perl/Exporter-circular-use
$ perl -v | head -n 2

This is perl 5, version 32, subversion 1 (v5.32.1) built for amd64-freebsd-thread-multi

2022-03-13 11:54:50 dpchrist@samba /var/local/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
# '
1..4
# Looks like you failed 1 test of 4.

Attachment: Exporter-circular-use-20220313-113141.tar.gz
Description: application/gzip

Reply via email to