I'm not sure I got how to define private functions right. When I'm writing a package mathematica, I just do this:
BeginPackage["myPackage`"]
myPublicFunction::usage="myPublicFunction blahblahblah";
Begin["Private"]
myPrivateFunction[input_]:= ... ;
myPublicFunction[input_]:= ... ;
End[]
EndPackage[]
Is this the correct way or am I missing something?
Yep, that's a correct way. It may pay off to understand some of the internal package mechanics. Mathematica contexts are similar to namespaces in other languages. They can be nested. Every symbol belongs to some context. At any given moment, some context is "current". Whenever a new symbol is created, the system must decide to which context the symbol will belong. This happens at parse-time. The fundamental quantity (variable) here is
$ContextPath
. It is basically the search path for symbols. It is a list of contexts, and whenever the system sees a new symbol, it tests if the symbol with the same short name (that is, the name of the symbol proper, without the context) exists in some context on the$ContextPath
. If it does exist, then the given occurrence of the symbol will be associated with that existing one. If it does not, then the symbol is created in a current context. Note that this is a dynamic thing - if you change the$ContextPath
at any moment, the next symbol occurrence can be associated with a different symbol.Anyways, what
BeginPackage
does is that it simply replaces the current value of $ContextPath with just{youPublicPackageContext, "System'"}
, plus possibly additional contexts that you publicly import through the second optional argument ofBeginPackage
. Therefore, all symbols that are in the "public" section, are parsed into the public context, if they are not in "System'" or other contexts that you import. And whatEndPackage
does is to restore the value of the$ContextPath
to what it was before you started loading the package. So, technically the usage message is not the only way to make a symbol public in your main context - you could just as well simply type a symbol with a semicolon, likemyFunction;
(this practice is discouraged, I just mentioned it to clarify the mechanism). Now, what happens when you enterBegin["'Private'"]
is that the current context becomesYourContext'Private'
(a sub-context). The$ContextPath
is not changed. Therefore, any symbol entered there, which does not exist in your public package or other imported packages (that is, contexts currently on the$ContextPath
), automatically is parsed into the'Private'
subcontext.What really makes these symbols private is that whenever you import your package into some other context (package), only the main package is added to the
$ContextPath
, but not its sub-packages. Technically, you can break encapsulation by manually addingYourPackage'Private'
to the $ContextPath (say,PrependTo[$ContextPath, YourPackage'Private']
), and then all your private functions and other symbols will become public in that particular context where you do the import. Again, this practice is discouraged, but it explains the mechanics. The bottom line is that the notion of private or public can be entirely understood when we know how symbols are parsed, and what are the manipulations with$ContextPath
and$Context
(another system variable giving the value of the current context), that are performed by commands such asBegin
andBeginPackage
. To put it another way, one could, in principle, emulate the actions ofBeginPackage
,Begin
,End
andEndPackage
with a user-defined code. There are just a few principles operating here (which I tried to outline above), and the mechanism itself is in fact very much exposed to the user, so that if, in some rare cases, one may want some other behavior, one can make some "custom" manipulations with$ContextPath
andContext
, to ensure some non-standard way of symbol parsing and therefore, control package-scale encapsulation in some "non-standard" way. I am not encouraging this, just mentioning to emphasize that the mechanism is in fact much simpler and much more controllable than it may seem on the surface.