32
$\begingroup$

A new package format is described in this post. This format does not use BeginPackage and Begin. Instead, each package file is scanned before its contents are evaluated, and the context of each symbol is decided beforehand.

What are some of the things to be aware when using this package format?

$\endgroup$
0

2 Answers 2

33
$\begingroup$

I will give a FAQ-style presentation of some things I became aware of while transitioning one of my packages to this format. Leonid's description of the new package format is required reading before looking at this FAQ!

How are contexts assigned to symbols in the package?

In traditional packages, symbols are looked up from $ContextPath, and if not found, created in $Context. It is always the current value of $ContextPath and $Context that determines what a symbol name in the package file refers to.

BeginPackage and Begin simply manipulate $ContextPath and $Context. When they are evaluated, the value of these system variables will change. End and EndPackage change it back. The process is dynamic, and happens as each line in the package file is evaluated one by one.

In new-style packages, the context of each symbol is decided before the contents of the package file are evaluated. Mathematica will scan all files in the package directory for the Package, PackageExport, PackageImport, PackageScope directives, and uses them to pre-determine the context of each symbol that appears in the package.

The package contents are evaluated only after this has happened.

Which contexts are symbols created in?

A private symbol in a file named Foo that is part of the package MyApp` will go in the context MyApp`Foo`PackagePrivate` .

A package scope symbol, declared with PackageScope, will go in MyApp`PackageScope` .

An exported symbol, declared with PackageExport, will go in MyApp` .

How do Package, PackageExport, PackageImport, PackageScope evaluate?

They do not evaluate at all. They are not expressions and hence they also cannot be terminated by a ; which is a short form for CompoundExpression.

They behave more like directives than symbols. They simply signal to the parser how to assign contexts to each symbol in the file. This assignment of contexts takes place before any evaluation is done.

This means that e.g. this is not valid:

PackageExport /@ {"symbol1", "symbol2"}

Instead we must write

PackageExport["symbol1"]
PackageExport["symbol2"]

PackageExport never evaluates as a symbol.

In what order are files loaded?

A new-style package is usually made up by multiple files, each containing Package["MyApp`"]. If the loading of one of these files is triggered with Get or Needs, all other files that belong to the MyApp` package will be loaded.

After the first file was loaded, the rest will be loaded in alphabetical order.

The first file would either have the same name as the package itself (e.g. MyApp.m for MyApp` ) or it would be explicitly loaded in Kernel/init.m.

What are valid file names?

Since file names are mapped to context names, file names must also be valid context names. This means that _ or a space cannot be used in file names. File names may not start with a digit.

It is a natural thought to try to control loading order by prepending digits to file names. But such names are not valid.

What is the value of $Context and $ContextPath during package loading?

In Mathematica 11.0 and later, the value of $Context and $ContextPath correspond to the file that is currently being loaded.

For example, if the current file is Main.m and the package name is MyApp` , then

$Context === "MyApp`Main`PackagePrivate`"
$ContextPath === {"MyApp`PackageScope`", "MyApp`", "System`"}

However, in Mathematica 10.x, $Context and $ContextPath do not change at all during loading. They retain the value they had before package loading (e.g. $Context === Global` and the usual $ContextPath).

What this means in practice is that in Mathematica 10.x, ToExpression["x"] would create the symbol x in the Global` context (or whatever was the context before package loading) instead of the package's private context.

The same is true for <*expr*> included in StringTemplates.

Finally, if the package loads another file with Get, all symbols in that file will be created in Global` , not in the package's private context.

What is the value of $InputFile and $Input when loading new-style packages?

In Mathematica 11.0 and later, $InputFile is always set to the specific file that is currently being loaded. It is different for each file that makes up the package.

In Mathematica 10.x, $InputFile is always set to the first file of the package, regardless of which file is currently being loaded.

$Input is always set to the name of the first file, in all versions between M10.0–M11.3.

Can we give a definition to Package?

Each file that is part of the package must include

Package["MyContext`"]

As explained before Package is just a directive, and does not have a definition. We might, in principle, give it a definition, and hope that it will evaluate in each package file.

This, however, does not happen. Package and related directives are removed from the file before its contents are evaluated.

$\endgroup$
2
  • 2
    $\begingroup$ Great job of outlining the more subtle points of new-style packages. Big +1. $\endgroup$ Commented Oct 26, 2018 at 20:48
  • 1
    $\begingroup$ It seems like in new format files constituting package have to have '.m' extension. Files with '.wl' extension are ignored except the main package file. $\endgroup$ Commented Mar 10, 2021 at 11:21
11
$\begingroup$

I would add to this that it is undocumented for a reason, unfinished, and may break in the future.

$\endgroup$
2
  • 7
    $\begingroup$ That, of course, technically applies to any undocumented feature. The problem is that there is an endless list of undocumented features which are in reality essential to developing packages with any sanity (from WithLocalSettings to not so long ago paclets themselves). Realistically one cannot do without undocumented features. Thus we need to consider the risk in each individual case. $\endgroup$
    – Szabolcs
    Commented Jan 20, 2021 at 8:20
  • 10
    $\begingroup$ Personally, I am quite conservative in this and use only features which have been stable for a long time and are used internally. This is the case with new-style packages (they worked mostly the same in v10 over 6 years ago, and are used by many internal components). I assume there is a reason you posted this, and there are plans, or at least discussions, to make drastic changes. I very much hope that there will be a reasonable way forward for those who have invested in this feature. $\endgroup$
    – Szabolcs
    Commented Jan 20, 2021 at 8:22

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.