Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What compile time features does Perl provide that other languages don't?

Is Perl considered a general purpose programming language?

Reading about it on Wikipedia

Perl has a Turing-complete grammar because parsing can be affected by run-time code executed during the compile phase.[41] Therefore, Perl cannot be parsed by a straight Lex/Yacc lexer/parser combination. Instead, the interpreter implements its own lexer, which coordinates with a modified GNU bison parser to resolve ambiguities in the language.

It is often said that "Only perl can parse Perl," meaning that only the Perl interpreter (perl) can parse the Perl language (Perl), but even this is not, in general, true. Because the Perl interpreter can simulate a Turing machine during its compile phase, it would need to decide the Halting Problem in order to complete parsing in every case. It's a long-standing result that the Halting Problem is undecidable, and therefore not even perl can always parse Perl. Perl makes the unusual choice of giving the user access to its full programming power in its own compile phase. The cost in terms of theoretical purity is high, but practical inconvenience seems to be rare.

So, it says that though Perl has the Turing complete badge, it is different from other languages because gives "the user access to its full programming power in its own compile phase". What does that mean? What programming power does Perl provide me at compiling phase that others don't?

like image 402
Lazer Avatar asked Dec 22 '22 00:12

Lazer


2 Answers

There are no features of Perl that do not appear in any other language. Lisp can do anything (Lisp is an example, here.). So perhaps we can narrow the question down to what are the features of Perl that make wide behavior swings an easy thing to do.

  • BEGIN blocks (END blocks, too.) which alter the behavior during compile. So I can write Perl code that changes the location of modules to be loaded.

    Even the following code might have a different meaning.

    use Frobnify;
    Frobnify->new->initialize;
    

    Because I could have changed where Frobnify loads from:

    BEGIN { 
        if ( [ localtime ]->[6] == 2 ) { 
            s|^/var|/var/days/tuesday| foreach @INC;
        }
    }
    

    So on Tuesdays, I load /var/days/tuesday/perl/lib/Frobnify.pm

  • Source Filters can programmatically edit the code that will perform. (CAVEAT on source filters!) (crudely and roughly equivalent to LISP macros)

  • Somewhat along with BEGIN blocks are @INC hooks. As I can modify @INC at the beginning to see change what gets loaded. I can set a subroutine at the front of the @INC array to load anything I want to load. The hook can receive a request to load Frobnify and respond to it by loading Defrobnify.pm.

  • Somewhat along with this is Symbol Manipuation. After loading Defrobnify.pm, I can do this:

    *Frobnify:: = \*Defrobnify::;
    

    Now Frobnify->new creates a Defrobnify object!

like image 148
Axeman Avatar answered Dec 28 '22 08:12

Axeman


Subroutine prototypes are a compile time feature that is more or less exclusive to Perl. Many of Perl's builtin functions impose special types of context on their arguments (scalar, list, reference, code-block, capture). Prototypes are a way of porting some of that functionality over to user defined subroutines.

For example, Perl allows you to effectively generate new syntactic constructs with the (&) prototype. This is used in modules like Try::Tiny to add try and catch keywords to the language:

    try {
            die "foo";
    } catch {
            warn "caught error: $_"; # not $@
    };

This works because try and catch are declared as sub try (&;@) { ... }. The sub name {...} syntax is equivalent to BEGIN { *name = sub {...} } which means it has a compile time effect. In the case of try, the (&;@) prototype tells the compiler that any time it sees the identifier try, the first argument must be a bare block, and following the block is an optional list.

This is just one example of prototypes, and they are able to do many other things:

$  imposes scalar context on an argument
&  imposes code context on an argument
@  imposes list context on an argument
%  imposes list context (with an even number of elements)
*  imposes glob context on the argument 
\$ imposes scalar reference context
\@ imposes array reference context
   ... for the rest of the sigils

Due to their power (and absence in other languages) prototypes can be confusing and are best used in moderation. (like every other advanced feature of Perl).

like image 37
Eric Strom Avatar answered Dec 28 '22 08:12

Eric Strom