In some of my work I have started doing a lot more with higher order and functional Perl programming. A good example is PGObject::Util::DBMethod which provides a way to declaratively map stored procedures in Postgres to object methods. I have linked to the source code on github above because it is a good example of where macros would be very helpful.

Now I will be the first to admit that in these cases, macros are not 100% necessary. The module above can accomplish what it needs to do without them. However the alternative, which means effectively creating a highly generalized anonymous coderef, setting up a custom execution environment for that coderef, and then installing the generalized coderef with the specific execution environment as a method has some significant drawbacks.

Here's the particular section that does the main work:
sub dbmethod { my $name = shift; my %defaultargs = @_; my ($target) = caller; my $coderef = sub { my $self = shift @_; my %args; if ($defaultargs{arg_list}){ %args = ( args => _process_args($defaultargs{arg_list}, @_) + ); } else { %args = @_; } for my $key (keys %{$defaultargs{args}}){ $args{args}->{$key} = $defaultargs{args}->{$key} unless $args{args}->{$key} or $defaultargs{strict_ar +gs}; $args{args}->{$key} = $defaultargs{args}->{$key} if $defaultargs{strict_args}; } for my $key(keys %defaultargs){ next if grep(/^$key$/, qw(strict_args args returns_objects) +); $args{$key} = $defaultargs{$key} if $defaultargs{$key}; } my @results = $self->call_dbmethod(%args); if ($defaultargs{returns_objects}){ for my $ref(@results){ $ref = "$target"->new(%$ref); } } if ($defaultargs{merge_back}){ _merge($self, shift @results); return $self; } return shift @results unless wantarray; return @results; }; no strict 'refs'; *{"${target}::${name}"} = $coderef; }

Now that is 40 lines of code and 30 lines of it go into the coderef which is executed when the method is actually run. This doesn't seem too much but it does the work of 5-10 lines of code in an imperative style. In other words, it is 5-6 times as long and intensive as it needs to be.

With macros, it would be quite possible to generate only the code needed for the specific function rather than creating a generalized case which has to handle many non-applicable inputs, and then create a context where it only gets what it needs.

Replies are listed 'Best First'.
Re: The Case for Macros in Perl
by BrowserUk (Patriarch) on Sep 13, 2014 at 03:56 UTC

    FWIW: I agree that the addition of true macro capability to perl would be extremely useful. Perhaps one of the top two most beneficial changes that could be made. Unfortunately, I don't think it will ever happen.

    Not because it's not a good idea; but because it would be impossible to do it efficiently as a third-party add-on (CPAN package) and very,very difficult (if not impossible) to implement it within the parser itself. Even if you could align all the skills and opinions required to make it happen.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Well, I did it once: Adding macros to Perl5.

      Admittedly it was mostly a prove of concept but it shows that technically it is doable... a different matter would be getting p5p to agree on adding the feature and on the macro syntax.

        getting p5p to agree on [anything]

        Obtaining positive opinions are always going to be harder than the skills; though you're in a class of very few in the latter regard.

        Shame it never made it in. That looks very well thought through. Applying an attribute to a subroutine is a) something I'd never thought of; b) (IMO) the perfect way to add it to the syntax,


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: The Case for Macros in Perl
by CountZero (Bishop) on Sep 13, 2014 at 14:25 UTC
    And what about source filters?

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics
Re: The Case for Macros in Perl
by Anonymous Monk on Sep 13, 2014 at 07:09 UTC

    I don't understand ... what are macros?

    my $you_ve_been_bacrod = eval niceMacro(...);

    macro? Filter::Macro?

        Actually thinking of something like a Lisp macro, in particular being self-processed source-code not merely on the textual level but on a level higher than that (below the perl 6 macro level though)

        In this specific case, my thinking is to create a text string and eval it and see if that is cleaner. But it would be nicer to be able to process statements of perl as statements of perl, not as strings which will hopefully compile.

      I don't understand ... what are macros?

      Textual substitutions made, once, inline, at compile time.

      • evals are made every time they are encountered, at runtime.
      • Source-code filters partially fit the bill, but are buggy, unreliable, and a maintenance nightmare.

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Actually I think evals and strings would be a good match for this use case because the primary use here is only done once, on module load (this could be done at near-compile time by putting the method generators in a BEGIN block).

        However this specific case would be more generally solvable as a compile time macro, i.e. expanding the macro call at compile time into exactly what you want. The only reason I haven't seriously considered going with eval and strings is I haven't had the time to put together a good proof of concept for comparison's sake. When I do, I may ask about clarity here or in the seekers forum.

        evals are made every time they are encountered, at runtime.

        Sure, right, but

        use MyFoo -macronic => <<'YO'; ... YO;
        ???
Re: The Case for Macros in Perl
by thomas895 (Deacon) on Sep 16, 2014 at 00:26 UTC

    Perl 4 had the -P option, which would run the C preprocessor over your script before compiling it. That was eventually removed(for better or for worse).

    Today, you'd want to use something described in perlfilter.

    -Thomas
    "Excuse me for butting in, but I'm interrupt-driven..."
Re: The Case for Macros in Perl
by locked_user sundialsvc4 (Abbot) on Sep 15, 2014 at 22:59 UTC

    If it were me, I would probably not prioritize macros as being particularly important.   I like to see, right there in front of me, the source-code that the interpreter is going to finally execute.   If I wanted to use macros to generate that source-code, I would probably do it as a separate step which generated a .pl file as its output, and I would not ask the language system to do that for me.   (I did very strange things along those lines using Template::Toolkit once, but I’ve sobered-up since then ...)

      I like to see, right there in front of me, the source-code that the interpreter is going to finally execute.

      That makes as much sense as a chocolate teapot, and survives the heat of reasoned thought for about as long.

      By that logic, you would never use subroutines -- much less those imported from a different file -- nor symbolic constants; nor enumerations; nor object methods.

      Hell. You couldn't possible use Perl; because it is actually executed as C; but then the C is actually assembler; and assembler is just a symbolic representation of the processor opcodes, so you would have to program in hex. But then hex is just a representation of the underlying binary, so you'll have to code in the binary to achieve your goal.

      Ah! Still then, the processor opcodes are actually translated into micro code before they can be executed...

      A macro -- done right -- is simply an abstraction just like subroutines or symbolic constants. A way of clarifying source code by allowing what the programmer reads to more closely reflect the purpose of the code -- the algorithm being implemented -- not the mechanics of that implementation.

      But then, logic never was your strong suit.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      That view makes a lot of sense for a lot of applications. Don't get me wrong. I think my college calculus professor was right when he said that in mathematics, power tools are ineligant when hand tools will suffice. That attitude won't lead you far wrong in software development either.

      The problem though is that power tools are sometimes better at some things than the hand tools are. In this case we can't generate through compiled Perl code alone an elegant function to provide the functionality so we are left with, as here, a baroque and generalized version, or we get to generate Perl as text strings, then compile it and install the resulting function in the symbol table.

      To some extent once you get into perl that generates functions and installs them in the symbol table, you are already outside hand tool territory. The question is what one can do to create elegant code at that point.

      Macros are helpful because they allow for better tailoring of the code generated. I don't think they should ever be a tool of first resort, but they can be really, really helpful in some areas.