develooper Front page | perl.module-authors | Postings from March 2022

Exporter and subroutine circular dependencies between modules

Thread Next
From:
David Christensen
Date:
March 13, 2022 20:14
Subject:
Exporter and subroutine circular dependencies between modules
Message ID:
c4a1dd1b-bfa5-2991-271b-360a6bb1ea0a@holgerdanske.com
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.
Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About