Davs
Davs

Reputation: 489

Perl multiple sub param without comma

Is it possible with pert to achieve the following syntax?

sub a {
    my ($first, $second) = @_;
    print "$first $second";
}

sub b {
    my ($param, $code) = @_;
    my $res = $code->();
    return "$param $res";
}

a 'param1' b 'param2' => sub { return "param3" };
#output would be "param1 param2 param3"

a is sub, which would get inside @_ 'param1' and whatever b (which would got 'param2' and a subref inside @_) returns. I like having no comma before 'b'. Is it possible?

Upvotes: 0

Views: 95

Answers (1)

amon
amon

Reputation: 57640

I strongly recommend against this. What is your motivation to omit the comma?

  • Language X doesn't require a comma here.

    Perl isn't X. There are a lot of features that X may have, but Perl doesn't. This also includes static typing, indentation-sensitive parsing, and Lisp-style macros. If you absolutely need X's features, maybe you should be using X.

  • I am writing a DSL in Perl where the comma would be annoying.

    I am aware of this trend to write elaborate APIs that remotely look like ordinary text, and calling them a “DSL”. They are not; a DSL requires you to actually parse something. And if you're writing an API, it would better be idiomatic in the host language. Even if that involves stray commas and such.

  • I really want to do this for whatever reason, no matter how fragile the result.

    In this specific case, I can write code to do as you wish. It uses the absurd and discouraged “dative“ form of method calls (also known as “indirect object notation”).

    The param1 will be a class on which we call the a method. The argument list will be a call to b:

    use feature 'say';
    
    package param1 {
        sub a {
            my ($first, $second) = @_;
            say "$first $second";
        }
    }
    
    sub b {
        my ($param, $code) = @_;
        my $res = $code->();
        return "$param $res";
    }
    
    a param1 b param2 => sub { "param3" };  # look, optional quotes for param1
    

    Of course, that's merely syntactic sugar for 'param1'->a(b(param2 => sub { 'param3' })). And it requires you to know all values of param1 in advance – unless you create an object first that wraps the first arg:

    use feature 'say';
    
    package MyApi {
        sub a {
            my ($first, $second) = @_;
            say "$$first $second";
        }
    }
    
    sub b {
        my ($param, $code) = @_;
        my $res = $code->();
        return "$param $res";
    }
    
    sub api($) { bless \shift() => 'MyApi' }
    
    my $param1 = api 'param1';
    a $param1 b param2 => sub { "param3" };
    

    But that's silly.

  • I still want to do this, but without that fragile nonsense. I also do not care about how much effort I have to expend to make this work.

    You can add keywords to the Perl parser that allow you to take over parsing. This requires you to have a certain amount of knowledge about Perl's parser API, and your code will not work on older Perls. Because you probably don't want to write your parser in C, you might want to look at something like Devel::Declare::Lexer, but these modules tend to be a bit iffy. Good luck to you!

Upvotes: 5

Related Questions