Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: prototype in anonymous subroutine

I am currently learning about Perls system of typeglobs and namespaces. So I wrote a module that takes two arguments the value and the name of a constant and exports the constant to the caller. The $package variable is equal to caller[2].

*{"$package::$name"} = sub () { return $value; };

This code above does the job of exporting a anonymous subroutine into the callers symboltable. Because my goal is to build my own constant-implementation the subroutine has a empty prototype which means its a read-only subroutine.

But this is my problem: the prototype does not work. So

print &TestConst; #works well
print TestConst(); #works well
print TestConst; #Name "main::TestConst" used only once: possible typo at testscript.pl line 7.

Is there something wrong in my thoughts? Is there another way of doing it?

like image 448
user2875983 Avatar asked Jul 04 '14 07:07

user2875983


People also ask

What is anonymous subroutine in Perl?

You can create an anonymous subroutine simply by omitting the name in a subroutine declaration. In every other respect, the declaration is identical to a named one. $rs = sub { print "hello \n"; }; This expression returns a reference to the newly declared subroutine.

What is Perl prototype?

A Perl function prototype is zero or more spaces, backslashes, or type characters enclosed in parentheses after the subroutine definition or name. A backslashed type symbol means that the argument is passed by reference, and the argument in that position must start with that type character.

How do you pass arguments to a subroutine in Perl?

You can pass various arguments to a Perl subroutine like you do in any other programming language and they can be accessed inside the function using the special array @_. Thus the first argument to the function is in [0],thesecondisin_[1], and so on.

What does @_ mean in Perl?

Using the Parameter Array (@_) Perl lets you pass any number of parameters to a function. The function decides which parameters to use and in what order.


1 Answers

You can define all the symbols you want during runtime, but prototypes will only affect code compiled afterwards since prototypes affect how calls to the sub are parsed and compiled. For example:

use strict;
use warnings;

package Foo;

BEGIN {
    *Foo::bar = sub () { 42 };
}

*Foo::baz = sub () { 43 };

my $bar = bar;
my $baz = baz;

print "bar = [$bar], baz = [$baz]\n";

If we run this, it dies with:

Bareword "baz" not allowed while "strict subs" in use at tprot.pl line 13.

That's a compile-time error caused by strict: the compiler saw the symbol baz and didn't know what it was, because the typeglob *Foo::baz does not get altered until runtime. But bar worked fine because it was defined in a BEGIN block, which executes immediately during compilation.

IOW, because barewords are ambiguous, Perl needs to know at compile-time whether it's a sub or something else. So you can install these during import (which executes in an implicit BEGIN block) but not at runtime.

Additionally, prototypes affect compilation semantics; a constant subroutine (like those made by constant.pm) gets optimized away. Other prototypes cause the parser to change its behavior (e.g. subs which can take code blocks.) The compiler has to know about all this stuff before calls to the sub are actually encountered in the code, so they can be parsed correctly. The code runs after everything is already parsed.

Calling a sub with explicit parens or with an ampersand does not have this restriction because Perl is smart enough at runtime to know that these are subroutine calls, and to look them up dynamically in the symbol table.

like image 124
friedo Avatar answered Oct 17 '22 06:10

friedo