On 10/18/2016 07:51 PM, David Mertens wrote:
> Note: the module Carp::Always can be a lifesaver in the occasion
> that you need a stack trace and don't have one!

[Post reordered for replies.]


I think I knew and forgot that.  Thanks for the reminder.


I did recall a technique from "Perl Testing: A Developer's
Notebook" [2] -- mocking up subroutines, objects, etc..  I played with
it on a simple circular subroutine example, and it kinda sorta worked.
With more study, I might be able to get better results.


> The strategy that I've seen is to place all constants in their own 
> module. (With the many-to-many file-to-package relationship, this 
> isn't a problem.) Then I frankly can't imagine circular dependencies 
> causing trouble. Of course, if one fails, all others will fail too, 
> but failure to compile is BUG #0, and in my experience Perl's 
> diagnostics usually pinpoint the problem without any confusion.
...
> The second strategy, if constants really are the source of pain, is 
> to have each module declare all of its constants first, then declare 
> circular dependencies. This way, by the time the compiler reaches
> any code that needs a constant, all of them will be available.

I am not have any trouble with constants, probably because mine are
literals or function calls with literals.


I've lumped together all the ASCII constants into one module for
convenience.  Likewise for the other "global" constants.  Constants that
relate to a particular module I put into that module near the top.


> I have no idea if my approach to circular dependencies is helpful. 
> Basically, I've never had problems, so I wonder if there's a design 
> approach you're using that's somehow more prone to this sort of 
> problem with Perl. Again, if you had some code to share, it would 
> help direct the conversation a bit more concretely.

Here is a contrived example that shows circular modular dependency
without circular subroutine dependency:

2016-10-19 11:05:08 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ cat Foo.pm
package Foo;
use strict;
use warnings;
require Exporter;
our @ISA = qw( Exporter );
our @EXPORT = qw( foo1 foo2 );
use Bar;
sub foo1 { print "foo1\n"; bar2(); }
sub foo2 { print "foo2\n";         }

2016-10-19 11:05:10 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ cat Bar.pm
package Bar;
use strict;
use warnings;
require Exporter;
our @ISA = qw( Exporter );
our @EXPORT = qw( bar1 bar2 );
use Foo;
sub bar1 { print "bar1\n"; foo2(); }
sub bar2 { print "bar2\n";         }

2016-10-19 11:05:12 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ cat foo
#!/usr/bin/perl
use strict;
use warnings;
use Foo;
foo1();

2016-10-19 11:05:16 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ cat bar
#!/usr/bin/perl
use strict;
use warnings;
use Bar;
bar1();

2016-10-19 11:05:18 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl -c Foo.pm
Subroutine foo1 redefined at Foo.pm line 8.
Subroutine foo2 redefined at Foo.pm line 9.
Foo.pm syntax OK

2016-10-19 11:06:48 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl -c Bar.pm
Subroutine bar1 redefined at Bar.pm line 8.
Subroutine bar2 redefined at Bar.pm line 9.
Bar.pm syntax OK

2016-10-19 11:06:51 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl foo
foo1
bar2

2016-10-19 11:06:53 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl bar
bar1
foo2


The compiler warns when compiling the modules, but the scripts compile
and run correctly without warnings or errors.


Now, add a bug to Foo.pm -- an extra left brace (one of my favorites):

2016-10-19 11:07:55 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ vi Foo.pm
package Foo;
use strict;
use warnings;
require Exporter;
our @ISA = qw( Exporter );
our @EXPORT = qw( foo1 foo2 );
use Bar;
sub foo1 {{ print "foo1\n"; bar2(); }
sub foo2 { print "foo2\n";         }

2016-10-19 11:08:00 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl -c Foo.pm
Missing right curly or square bracket at Foo.pm line 9, at end of line
syntax error at Foo.pm line 9, at EOF
Compilation failed in require at Bar.pm line 7.
BEGIN failed--compilation aborted at Bar.pm line 7.
Compilation failed in require at Foo.pm line 7.
BEGIN failed--compilation aborted at Foo.pm line 7.

2016-10-19 11:08:04 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl -c Bar.pm
Missing right curly or square bracket at Foo.pm line 9, at end of line
syntax error at Foo.pm line 9, at EOF
Compilation failed in require at Bar.pm line 7.
BEGIN failed--compilation aborted at Bar.pm line 7.

2016-10-19 11:08:09 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl foo
Missing right curly or square bracket at Foo.pm line 9, at end of line
syntax error at Foo.pm line 9, at EOF
Compilation failed in require at foo line 4.
BEGIN failed--compilation aborted at foo line 4.

2016-10-19 11:08:12 dpchrist@t7400 ~/sandbox/perl/circular-dependency
$ perl bar
Missing right curly or square bracket at Foo.pm line 9, at end of line
syntax error at Foo.pm line 9, at EOF
Compilation failed in require at Bar.pm line 7.
BEGIN failed--compilation aborted at Bar.pm line 7.
Compilation failed in require at bar line 4.
BEGIN failed--compilation aborted at bar line 4.


Yes, the compiler gives the same error message up front, four times, so
it's a good indicator of where the problem lies.  But when I had
multiple edits, lots of modules in the loop, and an earlier Perl,
finding and correlating the needles in the haystack was non-trivial.


> As for your testing approach, I mostly agree, but work on a 
> function-level heierarchy, not module-level heierarchy. Some 
> functions do not depend upon others; those are the ones I test
> first. Other functions that call the ones I've test come next, etc. I
> don't necessarily run these tests in strict order (all 0-level
> functions before all 1-level functions), but I do make sure to always
> test simple functions before testing dependent functions.

It sounds like I'm following a tried and proven path.  :-)


David

[2] http://shop.oreilly.com/product/9780596100926.do

Reply via email to