diotalevi has asked for the wisdom of the Perl Monks concerning the following question:

Is there any good way to inline method or function calls? Say an attribute on the method or something? I don't know of anything off hand and wanted to know if anyone here knew of anything in particular. There's an example of an inlined function in my newly uploaded ESPPlus::Storage::Record class - the alternative would have me replacing that block with a my $expt_len = $self->expected_length call. The only issue is that its in a speed sensitive section of code - so I'm trying to avoid extra runtime overhead.

Suggestions?

sub body { my $self = shift; if ( exists $self->{'uncompressed'} ) { return $self->{'uncompressed'}; } unless ( exists $self->{'compressed'} ) { confess "Record missing body!"; } my $expt_len; ## START Inline # Inlined the ->expected_length method call here. if ( exists $self->{'expected_length'} ) { $expt_len = $self->{'expected_length'}; } else { if( ${$self->{'header_text'}} =~ /L=(?>[^;]+);/ ) { $expt_len = substr ( ${$self->{'header_text'}}, $-[0] + 2, $+[0] - $-[0] - 3 ); } else { $expt_len = undef; } } ## END Inline $self->{'uncompressed'} = $self->{'uncompress_function'}( $self->{'compressed'}, $expt_len ); my $retr_len = length ${$self->{'uncompressed'}}; unless ( $expt_len == $retr_len ) { confess "Uncompressed record length $retr_len did not match expect +ed " . "length $expt_len for record $self->{record_number}."; } return $self->{'uncompressed'}; }

Replies are listed 'Best First'.
Re: Inlining method/function calls?
by Zaxo (Archbishop) on Jul 26, 2003 at 23:26 UTC

    There are two cases in perl which sort of correspond to inlining.

    One is the folding of constant functions in the compiler's optimization phase. That doesn't give you much direct control, but you can take pains to make perl notice the opportunity. Empty prototypes and constant.pm help there.

    The other, mentioned by adrianh, is to invoke the C preprocessor with the -P flag. An example,

    #!/usr/bin/perl -P #define Foo(a) {\ local $, = " ";\ print "defined: ", a, $/;\ } my ($c, $d, @e, %f) = ('c','d',qw/all in e/); @f{qw/all in f/} = @e; Foo($c) Foo($d) Foo(@e) Foo(%f)

    After Compline,
    Zaxo

      That is very cool! Right after I ran that snippet, I looked in 3rd Camel to see what it says, but it's quite sparse in what you can do. What is possible? Where could I go for more info, especially examples ...

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        The -P flag turns loose the C preprocessor on your source before perl ever sees it. Its behavior is determined by the C standard, at least for the portable parts. The handiest source of information is probably a C primer.

        In short, the C preprocessor makes direct textual substitution. with some logic available. I've never needed it for perl, but potentially useful constructs include,

        • #include "filename" - inclusion of source from another file.
        • #define foo some string or other - substitution macro definition
        • #if, #elseif, #else, and friends allow for conditional inclusion of source.
        None of this is really necessary to perl.

        After Compline,
        Zaxo

Re: Inlining method/function calls?
by broquaint (Abbot) on Jul 26, 2003 at 22:58 UTC
    If I understand your question correctly (something like C's inline, but for perl) then I'm afraid the answer is no, you can't inline functions/methods. This is largely due to the complex nature of perl and more directly its dynamic nature and handling of subroutines. Limbic~Region asked this question back in May at Inline subs? and I came up with a filter solution, but as noted in a reply, there are many, many issues with this. Although if I haven't understood your question then you can disregard the above ;)
    HTH

    _________
    broquaint

Re: Inlining method/function calls?
by adrianh (Chancellor) on Jul 26, 2003 at 22:58 UTC

    Inlining method calls is impossible since they're determined at runtime - you need to know what kind of object $foo is before you know what $foo->method means.

    You need the kind of typing hints that Perl6 will be giving us before you can do this sort of optimisation. Sorry :-)

      Ok, assume I'm willing to promise that the method / function won't change. In this case the method call was hardcoded in and can't change - I already circumvent perl's normal flexiblity.

        A source filter would seem the only solution in Perl5 - or, if you want something quick and dirty, using CPP via the -P command switch.

Re: Inlining method/function calls?
by fglock (Vicar) on Jul 27, 2003 at 02:44 UTC

    How about eval?

    # "inline subroutine" my $inlined = <<'END'; my $expt_len; ## START Inline # Inlined the ->expected_length method call here. if ( exists $self->{'expected_length'} ) { $expt_len = $self->{'expected_length'}; } else { if( ${$self->{'header_text'}} =~ /L=(?>[^;]+);/ ) { $expt_len = substr ( ${$self->{'header_text'}}, $-[0] + 2, $+[0] - $-[0] - 3 ); } else { $expt_len = undef; } } ## END Inline END # sub declaration eval <<'END' sub body { my $self = shift; if ( exists $self->{'uncompressed'} ) { return $self->{'uncompressed'}; } unless ( exists $self->{'compressed'} ) { confess "Record missing body!"; } END .$inlined. <<'END'; $self->{'uncompressed'} = $self->{'uncompress_function'}( $self->{'compressed'}, $expt_len ); my $retr_len = length ${$self->{'uncompressed'}}; unless ( $expt_len == $retr_len ) { confess "Uncompressed record length $retr_len did not match expect +ed " . "length $expt_len for record $self->{record_number}."; } return $self->{'uncompressed'}; } END ;
Re: Inlining method/function calls?
by BrowserUk (Patriarch) on Jul 28, 2003 at 02:56 UTC

    Suggestion. Perform the test for existance inline and only call the function if the value must be extracted from the header. The overhead of the function call will likely be lossed in the code of invoking the regex engine.

    Question: Why do you use that substr expression? You have captured the value to $1 (if it exists) in order to set @- and @+. Why not just use $1?


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller

      Because capturing is the most expensive thing that happens there. On a ten minute program I shaved a minute off by avoiding capturing groups (you mistook (?>...) for a capture block) and using substr instead. A minute is pretty small for the thirty megabyte data set I was working with, I just expected most data sets to be half a gig or more. I picked a simpler example for this code sample - it still illustrates the point (and verified through dprof).

      unless ($$buffer =~ m/^H=(?>\d+);/) { confess "$rec_num was missing the header prefix m/^H=\\d+;/: $$buf +fer"; } my $header_length = substr $$buffer, 2, $+[0]-3; # vs unless ($$buffer =~ m/^H=((?>\d+));/) { confess "$rec_num was missing the header prefix m/^H=(\\d+);/: $$b +uffer"; } my $header_length = $1;