11

I was playing around with a Perl 6 implementation of a command-line program that takes several switches. The signature to MAIN was quite involved and a bit messy. I wondered if there was a way to define the signature somewhere else and tell the subroutine what to use:

# possibly big and messy signature
my $sig;
BEGIN { $sig = :( Int $n, Int $m ) };

multi MAIN ( $sig ) {
    put "Got $n and $m";
    }

MAIN doesn't see the variables in the signature even though the signature is set before MAIN compiles:

===SORRY!=== Error while compiling /Users/brian/Desktop/signature.p6
Variable '$n' is not declared
at /Users/brian/Desktop/signature.p6:7

I figured this sort of thing might be handy for generating methods after compile time and selecting signatures based on various factors.

Pat
  • 36,282
  • 18
  • 72
  • 87
brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • Whatever is in `(…)` is the signature, so that is never going to work. The way you would do this would be low-level and implementation specific. I would try to do this my having a generic signature, and forcefully alter the signature after it gets parsed. That's ignoring the rigamarole to alter the multi dispatcher. – Brad Gilbert Jan 08 '17 at 14:38
  • In order for the variables inside the function to not throw "variable not declared" errors, this would have to be done at compile time by something like a macro. Unfortunately, the macro/slang functionality that was planned for Perl 6, hasn't materialized yet. – smls Jan 09 '17 at 05:00
  • On a side note: You can declare a variable in the top-level scope and initialize it at BEGIN time in one statement, by using the block-less form of the BEGIN phaser: `BEGIN my $foo = ... ;` – smls Jan 09 '17 at 05:02

1 Answers1

9

Short answer: No

Long answer: Still no. And if you could, you'd run into all kinds of trouble, because there's only one variable $n in your example. If you use the signature multiple times (or use it only once, and recurse into the subroutine that you attached it to), each signature binding would overwrite the previous value in that variable, causing some spooky action at a distance. There simply isn't a mechanism to cloning the variables involved in a free-floating signature.

Workarounds like using a match-all signature in the actual routine, and then use that to bind the capture to the signature suffer from this same flaw, and are thus IMHO not worth the trouble.

Maybe in the far future, some very advanced Macro feature might allow you to transplant signatures, but I don't think that part of macro development is even on our roadmap right now.

Instead of reusing bare signatures, you should reuse (possibly anonymous) routines with a signature attached, and install them with the name you want, for example

sub f(Int $n, Int $m) {
    # do something sensible here with $n and $m
}
constant &MAIN = &f;
# reuse &f for more 
moritz
  • 12,710
  • 1
  • 41
  • 63
  • Then what's the point of declaring standalone signatures, if they can't be used anywhere? – jjmerelo Feb 15 '18 at 09:43
  • 3
    The point is, I think, that you can smartmatch a given (literal) `Signature` with the signature of a `Block`, e.g. `sub a($a) { }; dd &a.signature ~~ :($b)` – Elizabeth Mattijsen Feb 15 '18 at 13:20