Recipe 12.5 Making Functions Private to a Module

12.5.1 Problem

You want to make a function private to a package.

12.5.2 Solution

You can't. But you can make a private variable and store a reference to an anonymous function in it.

# this is the file
package Some_Module;

my $secret_function = sub {
    # your code here

sub regular_function {
    # now call your "private" function via the code ref
    $secret_function->(ARG1, ARG2);

12.5.3 Discussion

Even a function that isn't exported can still be accessed by anyone, anywhere if they qualify that function's name with its package. That's because function names are always in the package symbol table, which is globally accessible.

By creating a lexical variable at the file scope, code in that module file below the point of declaration has full access to that variable. Code in other files will not, because those scopes are unrelated. The subroutine created via sub { .... } is anonymous, so there's no name in the symbol table for anyone outside to find. Not even other code in the module can call the function by name, since it doesn't have one, but that code can use the lexical variable to dereference the code reference indirectly.

$secret_function->(ARGS);                # infix deref form
&$secret_function(ARGS);                 # prefix deref form

Curiously, if you really wanted to, you could give this anonymous function a temporary name. Using the technique outlined in Recipe 10.16, assign the code reference to a localized typeglob, like this:

sub module_function {
    local *secret = $secret_function;
    Other_Package::func1( );
    secret(ARG1, ARG2);
    Yet_Another_Package::func2( );

Now for the duration of module_function, your previously secret function can be called using a direct function call; no indirection required. However, code outside the module can also find that function. In the example, it doesn't matter whether func1 and func2 are in the module's file scope, because you've made a temporary symbol table entry through which they could get at your secret function. Therefore, if Other_Package::func1 turned around and called Some_Module::secret, it could find itbut only if func1 were called from the module_function in the example. If it were called from some other point, there wouldn't be any secret function in the Some_Module package symbol table, so the attempted function call would fail.

This slightly peculiar behavior, where temporaries' values and visibility depend upon who called whom at runtime, is called dynamic scoping. This is the nature of the local keyword. You can see why we don't usually suggest using it.

12.5.4 See Also

Recipe 12.4; the section on "Dynamically Scoped Variables: local" in Chapter 4 of Programming Perl; the section on "Symbol Tables" in Chapter 10 of Programming Perl