Skip to content

Conversation

leonerd
Copy link
Contributor

@leonerd leonerd commented Sep 15, 2025

  • Added ->ambient_pragmas_from_caller method for simplicity
  • Add best-effort fallback deparse of OP_MULTIPARAM to prior pure-perl behaviours
  • Add unit test of such
  • Add documentation that points out what it does and alerts users to the fact this may not always work in future

Currently no perldelta, but I could be convinced to add one if considered significant. Do we normally include changes to bundled modules in perldelta?

@book
Copy link
Contributor

book commented Sep 15, 2025

I really appreciate the (best) effort put into this.

I only use B::Deparse to get a better understanding of code, and (more often than not) to show people who don't know Perl very well how some code excerpt is understood by Perl itself. Usually, by doing something like:

perl -MO=Deparse -e '...'

I don't think this kind of usage will trigger the behaviour described with regard to "ambient pragmas", though.

@leonerd
Copy link
Contributor Author

leonerd commented Sep 15, 2025

Indeed so. In the usual -MO=Deparse scenario, it prints entire packages or at least entire subs, complete with the surrounding context:

$ perl -MO=Deparse,func -E 'sub func($x, $y, $z = 2) {}'
use feature 'current_sub', 'bitwise', 'evalbytes', 'fc', 'isa', 'module_true', 'postderef_qq', 'say', 'signatures', 'state', 'try', 'unicode_strings', 'unicode_eval';
use builtin (':5.40');
sub func ($x, $y, $z = 2) {
    ;
}
-e syntax OK

Copy link

@bram-perl bram-perl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you planning to merge this?

  • Branch as is?
  • Squashing some commits and fast-forward merge (i.e. no merge commit)
  • With a merge commit?

My personal view: there are definitely some commits that I would keep separate (i.e. the tidying up) .

warning_bits => $warning_bits,
'%^H' => $hinthash,
);
$deparse->ambient_pragmas_from_caller;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit tests for ->ambient_pragmas_from_caller

This commit is slightly confusing; that it: when seeing the commit title I would've expected tests for the ambient_pragmas_from_caller function but what it is doing is using it inside the tests.

(If that is all that was intended then fine; I'm not asking for explicit tests for the ambient_pragmas_from_caller it's just what I expected to see in the commit)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah that was more of a note to myself to remind me. I'll just squash it in to the previous commit.

lib/B/Deparse.pm Outdated
Comment on lines 1320 to 1323
foreach my $parami ( 0 .. $#param_padix ) {
my $argix = $parami;

$code .= "my $param_padname[$parami] = ";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit Best-effort deparse of OP_MULTIPARAM when feature 'signatures' is disabled

Reading up a bit on signatures, in perlsub, it contains:

An optional parameter can be nameless just like a mandatory parameter. For example,

sub foo ($thing, $ = 1) {
   print $thing;
}

The parameter's default value will still be evaluated if the corresponding argument isn't supplied, even though the value won't be stored anywhere. This is in case evaluating it has important side effects. However, it will be evaluated in void context, ...

It's not yet clear to me how/if this is handled.

(But I'm not that familiar yet with this code and/or signatures so I might be overlooking something)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not yet clear to me how/if this is handled.

Ooh, good catch. I don't have a test for that yet, and in fact I'm not sure the code will even handle it. Looks like more work to do there.

lib/B/Deparse.pm Outdated
as possible. This is performed on a B<best-effort> basis. It is not
guaranteed to perfectly capture the semantics of the signature's behaviour,
only to offer a human-readable suggestion as to what it might do.
Furthermore. it is not guaranteed to be able to reproduce every possible

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit Add docs to B::Deparse about signatures pure-perl fallback

Furthermore. --> Furthermore, ?

@leonerd
Copy link
Contributor Author

leonerd commented Sep 19, 2025

Squashing some commits and fast-forward merge (i.e. no merge commit)

Yeah I'll squash some of them out and preserve the identity of others. I'll have a hack at that now.

Add C<...> wrapping around the name of the module, also a few other
places. Also add L<...> wrapping around names of other modules.
@leonerd
Copy link
Contributor Author

leonerd commented Sep 19, 2025

Rebased, squashed some commits, fixed a few more little docs issues, added code + tests for anonymous signature params.

PTAL.

Comment on lines +590 to +591
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit Unit tests for B::Deparse coderef2text on signatured sub with signatures feature enabled

Slightly wondering: should $deparse->ambient_pragmas_from_caller; be called after the test(s) to reset the state?
In the earlier block of code (line 96) it does happen explicitely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's probably no huge need to reset it after some tests, as any newly-added test block that gets added after this may want to set it back to something else for its own purposes anyway.

Comment on lines 1346 to 1353
else {
# anonymous params without defaulting expressions can be entirely ignored
$param_padix[$parami] or next;

$stmt .= "\$_[$argix]";
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit Best-effort deparse of OP_MULTIPARAM when feature 'signatures' is disabled

While the code works it was a bit confusing at first.
I would probably write this as:

        if (my $defmode = $param_defmode[$parami]) {
            ...
        }
        elsif (not $param_padix[$parami]) {
            # anonymous params without defaulting expressions can be entirely ignored
            next;
        }
        else {
            $stmt .= "\$_[$argix]";
        }

The check is also inconsistent with the earlier check. Earlier check (on line 1130):

            if( length $param_padname[$parami] > 1 ) {

while here it just checks for a true value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the code works it was a bit confusing at first. I would probably write this as:
...

I wanted to structure it in two branches, for optional vs. mandatory params, and within each branch then have a condition for anonymous versions of those. It's two binary choices, not a threeway split.

The check is also inconsistent with the earlier check. Earlier check (on line 1130):
...
while here it just checks for a true value.

Ohyes, hmm. That's quite subtle.

Anonymous mandatory params don't even get allocate a pad slot, so their padname is undefined. Anonymous optional params need a pad slot to detect if it's been set or not, and therefore have a name that is simply '$'. So the conditions for detecting named vs. anonymous params are different depending if they're optional or mandatory.

I have explained further in some more comment.

foreach my $parami ( 0 .. $#param_padix ) {
my $argix = $parami;

my $stmt = "my $param_padname[$parami] = ";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit Best-effort deparse of OP_MULTIPARAM when feature 'signatures' is disabled

Can $param_padname[$parami] be undef? (If so then it will trigger a warning)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the name is always at least '$'

lib/B/Deparse.pm Outdated

# anonymous params with defaults don't create or assign a variable but
# still evaluate the defaulting expression for side-effects
if( length $param_padname[$parami] > 1 ) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit Best-effort deparse of OP_MULTIPARAM when feature 'signatures' is disabled

nit-picking: style seems appears inconsistent?
Earlier if-blocks are all if (...) { while this is if( ... ) {

(if/when intentional then feel free to ignore)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahyes, fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants