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

Hi

is there a way to tell the compiler to parse barewords (when allowed) as sub-calls and not as strings w/o predeclaring them?

use strict; use warnings; use feature 'say'; our $AUTOLOAD; sub AUTOLOAD { say "Autoload called as $AUTOLOAD(@_)" } BLA(1,2,3); no strict 'refs'; # BLA 1,2,3;

motivation

I'm experimenting with internal DSLs and am also looking at some Ruby examples.

Since Ruby never tries to interpret barewords as strings¹ it tries to call it's own version of AUTOLOAD() there ( IIRC .missing_method())

For this in Perl I need to use parens.

Uncommenting BLA in the code example leads to error with Do you need to predeclare BLA

Many DSLs profit (i.e. have much more syntactic sugar) if calls are not necessarily predeclared.

Semantically it's a way to avoid method syntax in a special context, i.e instead of writing

$myDSL->BLA + $myDSL->FOO

I can use

 within_myDSL { BLA + FOO }

But ATM I can only achieve

 within_myDSL { BLA() + FOO() }

I don't have much hope here, but asking shouldn't be a sin.

Cheers Rolf

( addicted to the Perl Programming Language)

¹) In Perl a (non strict) heritage from shell scripting

Replies are listed 'Best First'.
Re: Parsing barewords as sub/method calls?
by hdb (Monsignor) on Nov 23, 2013 at 18:01 UTC

    This looks interesting but I do not fully understand.

    You do not want to pre-declare also not to pollute the callers naming space. Does this mean that for the following code

    BLA 1,2,3; within_myDSL { BLA 1,2,3 }

    the first BLA should raise an error, whereas the second one would call AUTOLOAD?

    That looks difficult to achieve.

    I thought to move the pre-declaration into the package like this:

    use subs qw( BLA ); package iDSL; # package code 1;

    but that would pollute the callers space as well.

    More generally, how would one define such an internal DSL, so that code like within_myDSL { >>different rules here<< } is possible?

      > That looks difficult to achieve.

      yeah not trivial, you need to temporarily redefine AUTOLOAD in the callers package:

      use strict; use warnings; use feature 'say'; package DSL; our $AUTOLOAD; sub within (&) { my $c_block=shift; #say my $call_pkg=((caller)[0]); # use B::Deparse; # say B::Deparse->new()->coderef2text($c_block); no warnings qw/redefine once/; no strict qw/refs/; local *{ ${call_pkg} . "::AUTOLOAD" } = sub { say "Autoload called as $AUTOLOAD(@_)" }; $c_block->(); } package TEST; DSL::within { &BLA; BLUB(2,3,4); }; # with import sub within (&); *within=\&DSL::within; within { &BLAi; BLUBi(2,3,4); }; BLX(); __END__ Autoload called as TEST::BLA() Autoload called as TEST::BLUB(2 3 4) Autoload called as TEST::BLAi() Autoload called as TEST::BLUBi(2 3 4) Undefined subroutine &TEST::BLX called at /home/lanx/perl/exp/DSL.pl l +ine 48.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      updates

      code extended

Re: Parsing barewords as sub/method calls? (workaround)
by LanX (Saint) on Nov 23, 2013 at 16:54 UTC
    Well found kind of a workaround:

    In the case of arguments for a undeclared bareword putting parens around them is mostly acceptable (syntactically sweet enough)

    And without arguments prepending an ampersand helps.

    This works w/o messing with strict.

    use strict; use warnings; use feature 'say'; our $AUTOLOAD; sub AUTOLOAD { say "Autoload called as $AUTOLOAD(@_)" } BLA(1,2,3); &BLA; no strict 'refs'; #&BLA 1,2,3; __END__ Autoload called as main::BLA(1 2 3) Autoload called as main::BLA()

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    update

    thanks for pointing out the special meaning of &NAME;, I was aware of it and as Eily pointed out, it's not a problem in this special case.

      Note that &BLA; has the interesting side effect of passing @_ through:

      use strict; use warnings; use feature 'say'; our $AUTOLOAD; sub AUTOLOAD { say "Autoload called as $AUTOLOAD(@_)" } sub BLUBB { say "BLUBB called with @_"; &BLA; }; BLUBB( 1,2,3 );

      &BLA; is actually equivalent to BLA(@_);. This works in your case because @_ is empty, but if you use this syntax within a sub, you'll forward its arguments.

      use feature 'say'; @_ = qw/4 5 6/; our $AUTOLOAD; sub AUTOLOAD { say "Autoload called as $AUTOLOAD(@_)" } BLA(1,2,3); &BLA; __END__ Autoload called as main::BLA(1 2 3) Autoload called as main::BLA(4 5 6)

Re: Parsing barewords as sub/method calls?
by oiskuu (Hermit) on Nov 23, 2013 at 17:43 UTC
    Also worth noting what perlsub says:
    In fact, if you predeclare functions you want to call that way, you don't even need parentheses:
    use subs qw(date who ls); date;
    I guess you might give e.g. use subs 'AAA'..'ZZZ';
      as I said

      > > w/o predeclaring them?

      Sometimes it's not possible to predeclare them.

      Also please note that predeclaring them involves polluting the callers package.¹

      sub predeclared; within_my_DSL { predeclare };

      Thats not always desirable.

      And the whole dynamic AUTOLOAD-mechanism doesn't make sense in combination with predeclared subs.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      update

      ¹) interesting question which comes up now, is if (and how) Ruby solves this... I suppose they don't care.

        What about the reverse? If within takes a code block, then a closure is formed with all the outer lexicals. Your caller now pollutes the DSL?