5
$\begingroup$

I want to make Private functions.

From my point of view, being a Private function means that the function is not accessible from other packages. For that purpose I wrote the following code. But my private function can be called in another package. I don't want that.

(*Package 1*)
BeginPackage["Test1`"];
Begin["`Private`"];
Test1`Private`function1[x_] := x
End[];
EndPackage[];
(*Package 2*)
BeginPackage["Test2`"]
function2[x_] := Test1`Private`function1[x]
EndPackage[]

As you can see from the above code, function1 is a private function in Test1. That same function when called in Test2 is still accessible, but I don't want that.

How can I resolve this.

Can anyone help me?

$\endgroup$
9
  • 2
    $\begingroup$ Perhaps you would care to explain why you want this behaviour? $\endgroup$
    – user21
    Apr 30, 2013 at 13:45
  • $\begingroup$ @ruebenko for functions protection purpose.I want like that $\endgroup$
    – subbu
    Apr 30, 2013 at 13:49
  • $\begingroup$ from what do you want to protect it? It can not be done. $\endgroup$
    – user21
    Apr 30, 2013 at 13:55
  • 3
    $\begingroup$ If you're trying to protect against accidentally calling the Test1 private function from outside that context, then just don't use its context inside Test2. If, however, you're trying to hide the definition of that private function, use other techniques, e.g., Encode. $\endgroup$
    – murray
    Apr 30, 2013 at 14:49
  • 1
    $\begingroup$ Unless the package is loaded before the user has a chance to execute code, they can't. The definitions of most of the built-in functions, including Unprotect, SetAttributes, and SetDelayed, can be modified, and there is no guarantee that they work as advertised at the time the package is loaded. Any tricks played by the package to hide the function from the user can also be played on the package to disable the hiding functionality. $\endgroup$ Apr 30, 2013 at 23:18

2 Answers 2

9
$\begingroup$

The following should make it pretty difficult to use function1 elsewhere:

BeginPackage["Test1`"];
f2::usage = "f2 usage message";
Begin["`" <> StringJoin @@ RandomChoice[CharacterRange["a", "z"], 30] <> "`"];
function1[x_] := x;
f2[x_] := 2 function1[x];
SetAttributes[f2, {Protected, ReadProtected, Locked}];
End[];
EndPackage[];

The trick is not to use the Private context, but a randomly named one.

f2, which uses function1, just works:

f2[2]

4

However, no information about function1 is leaked:

?function1

Information::notfound: Symbol function1 not found. >>

?? f2

f2 usage message

Attributes[f2]={Locked,Protected,ReadProtected}

Saving this using Encode and reading it using Get will prevent most casual users from peeking into the function's definition.

$\endgroup$
5
  • 2
    $\begingroup$ Khm, what about code completion or just plain old Names["Test1`*`*"] $\endgroup$
    – Ajasja
    Apr 30, 2013 at 15:33
  • $\begingroup$ The way I understood the OP's question, "The trick is not to use the Private context" in the other package is the right answer here. +1 $\endgroup$ Apr 30, 2013 at 15:55
  • $\begingroup$ @Ajasja Something like: Unprotect[Names]; Names["Test1**"] = "Nothing here"; Protect[Names]; SetAttributes[Names, Locked]; ? BTW Code completion stops for me at Test1` . I don't get anything more than that. $\endgroup$ Apr 30, 2013 at 16:17
  • $\begingroup$ @Ajasja ?"Test1**" leaks information too. I guess I'd have to overload that as well. $\endgroup$ Apr 30, 2013 at 17:50
  • 1
    $\begingroup$ If the objective is to make these functions uncallable except at package load time, perhaps it's worth adding a Condition on $Context as well? Or maybe pass an additional argument that has to take a particular (secret) value in order for the function to work? $\endgroup$ May 1, 2013 at 3:03
3
$\begingroup$

You could make your function an inline function.

BeginPackage["Test1`"];
(*this is a function with several invocations, which we'd like to inline*)
function2[x_Integer] := 2 + 1
function2[x_Symbol] := x

ReleaseHold[
  Hold[
    (*Non-private definitions go here*)
    privateCaller[y_] :=
      (Print["This is some functionality."];
       function1[y]+function2[y]
      )
  ] /.
    (*inline definitions go here*)
    {
      function1[y_] :> (Print["function1 is not a defined function."]; y),
      With[{z = DownValues[function2]}, patt:function2[x_] :> Replace[patt, z]]
    }
]
Clear[function2]
EndPackage[]

After EndPackage, the symbols function1 and function2 have no downvalues, so unless the user can read your package definitions (which they can, if they are determined), they have no way to invoke these functions.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.