MooseX::Extended versus the debugger

I've released MooseX::Extended 0.35 and it resolves a long-standing bug. If you tried to use multi subs, it would trigger this bug in Syntax::Keyword::MultiSub. To fix that, you had to manually patch the latter module:

--- old/lib/Syntax/Keyword/MultiSub.xs  2021-12-16 10:59:30 +0000
+++ new/lib/Syntax/Keyword/MultiSub.xs  2022-08-12 10:23:06 +0000
@@ -129,6 +129,7 @@
 redo:
     switch(o->op_type) {
       case OP_NEXTSTATE:
+      case OP_DBSTATE:
         o = o->op_next;
         goto redo;

Not good. However, Syntax::Keyword::MultiSub 0.03 has been released with that patch included, so that's a relief.

However, I was still struggling with switching WebService::OpenSky to MooseX::Extended but under the debugger, we have a serious problem.

This error pops up, making the debugger useless:

The 'add_attribute' method cannot be called on an immutable instance at ...

When you use MooseX::Extended, it takes years of best practices that have evolved for Moose and applies them to your Moose classes. Using this module is sort of equivalent to this:

package My::Class {
    use v5.20.0;
    use Moose;
    use MooseX::StrictConstructor;
    use feature qw( signatures postderef postderef_qq );
    no warnings qw( experimental::signatures experimental::postderef );
    use namespace::autoclean;
    use Carp;
    use mro 'c3';

    ... your code here

    __PACKAGE__->meta->make_immutable;
}
1;

That's right: you no longer need to remember to declare your classes as immutable, or even end them with a true value. But ... automatically making your classes immutable has a trade-off. It relies on B::Hooks::AtRuntime and when using that under the debugger, the hook is triggered too early, making your classes immutable before Moose has built them! Oops.

Early versions of MooseX::Extended fixed this by automatically disabling the immutable behavior when running under the debugger, but I reverted that after haarg filed a ticket, explaining the issue. B::Hooks::AtRuntime was patched to fix this, but I still get the error with the new code, so this is still an unresolved issue.

That's where WebService::OpenSky comes in. I wanted to use MooseX::Extended in some non-trivial code, but the debugger issue kept biting me. I finally fixed it with this:

package WebService::OpenSky::Moose;

use MooseX::Extended::Custom;
use PerlX::Maybe 'provided';

# If $^P is true, we're running under the debugger.
#
# When running under the debugger, we disable 
# __PACKAGE__->meta->make_immutable
# because the way the debugger works with B::Hooks::AtRuntime
# will cause the class to be made immutable before the Moose class
# is fully built. This causes the code to die.
sub import ( $class, %args ) {
    MooseX::Extended::Custom->create(
        includes => 'method',
        provided $^P, excludes => 'immutable',
        %args
    );
}

I think it's an elegant little hack, with the caveat that your code behavior might change under the debugger. Very frustrating. However, for those who want to use MooseX::Extended, I'm thinking about this change:

use MooseX::Extended
    debugger_excludes => [qw/autoclean immutable/];

That disables both namespace::autoclean and the immutable behavior under the debugger, but you have to ask for this behavior rather than have it happen silently. That being said, I don't like this proposal. We are changing the behavior and other modules can trigger $^P to be true, so I can't guarantee we're truly under the debugger. You could have key features disabled in production code.

MooseX::Extended is a lovely module for writing Moose classes in a safer manner, but this little nit is frustrating

Suggestions welcome.

Leave a comment

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/