Here's how I do this. I have a standard load script I build from template for all of my packages. You can see one for my main development package here.
What it does then is look for a directory called Packages in the top-level package directory (although there are config options to change this, if I remember correctly).
Then if the directory structure looks like:
MyPackage
Packages
+ pkg1.m
+ pkg2.m
A
+ subpkg1.m
B
+ subpkg2.m
I'll get out three contexts, "MyPackage`", "MyPackage`A", "MyPackage`B`". The way I then make all the symbols in each see eachother when they load is that I use lazy-loading. So first I scan through all the found package files and register all the symbol names in the appropriate context and setup an OwnValues pattern so that when they're called for the first time they will load the package they're declared in using a special PackageGet function. This is done by the PackageDeclare function in the load script.
That PackageGet function then uses Internal`WithLocalSettings and System`Private`NewContextPath and System`Private`RestoreContextPath to set up a $ContextPath that looks like:
{
"MyPackage`",
"MyPackage`A`",
"MyPackage`B`",
"MyPackage`PackageScope`Private`" (* I put a bunch of utility functions here *)
}
This way each symbol sees each other when they load, but no private declarations or anything like that.
I haven't fully described what I do, as I also have ways to handle circular dependencies and things, but this is a basic overview that perhaps one might implement for themselves.
I have found it to be a useful and powerful idiom reminiscent of the way python handles package loading.
Common.mpackage containing the private functions that will be shared among other packages that need those functions. – J. M.'s missing motivation Oct 01 '18 at 18:05Common.msolution is that JITL (Just-in-time-loading viaDeclarePackage) doesn't support a "names file". The drawback with a new-style package is that it is not scalable in terms of supporting JITL. If these two aspects are important (and they aren't always) but I argue they increase in importance with the size of a system so they might be for a "fairly large project". I am putting out shortly an extension ofBeginPackage-EndPackage(which I will link to) that addresses this very issue. – Ronald Monson Oct 01 '18 at 20:07DeclarePackageis an old style of doing this, which is no longer used, at least not internally in the company. The current mechanism is to use the paclet symbol autoloading and paclet project loading, which plays well with new-style packages. – Leonid Shifrin Oct 01 '18 at 20:31Stubattribute transfers as previously discussed ( I'm not just talking about public functions but private ones the OP mentions e.g. what if you want these privately shared functions to incorporate JITL? can the current mechanism handle this?). My sense is that this new mechanism is tilted towards public functions. Naturally, I don't fully understand paclet symbol autoloading so ... – Ronald Monson Oct 01 '18 at 21:07BeginPackage/EndPackagewhose ongoing presence seems unlikely to be deprecated anytime soon but I agree, to have a flowchart for what idioms might be reasonably adopted by developers in given situations would be great. – Ronald Monson Oct 01 '18 at 21:10