Why are the packages expl3 and xparse not marked as loaded with recent LaTeX 2ε-kernels

expl3packagesxparse

With recent LaTeX 2ε-kernels things of expl3 and xparse are available by default.

Why are the packages expl3 and xparse not marked as loaded with recent LaTeX 2ε-kernels?

With the example

\makeatletter
\message{^^J}
\message{xparse\@ifpackageloaded{xparse}{}{ not} loaded.^^J}
\message{expl3\@ifpackageloaded{expl3}{}{ not} loaded.^^J}
\message{\string\NewDocumentCommand\@ifundefined{NewDocumentCommand}{ not}{} defined.^^J}
\message{\string\ExplSyntaxOn\@ifundefined{ExplSyntaxOn}{ not}{} defined.^^J}
\stop

I get:

This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2020-10-01> patch level 4
L3 programming layer <2021-02-18> 
xparse not loaded.
expl3 not loaded.
\NewDocumentCommand defined.
\ExplSyntaxOn defined.
 )
No pages of output.
Transcript written on test.log.

Best Answer

In both cases, the core code of each package is loaded in the LaTeX kernel: for expl3, expl3-code.tex is preloaded, and for (former) xparse, its core command-definition facilities are built into the kernel, and the packages are still around mostly for compatibility.

There are two main reasons that the packages per se are not marked as loaded. The first are options: if the kernel preloaded, say, expl3 with no option, then an user tried to \usepackage[enable-debug]{expl3}, it would throw an “Option clash” error, so that cannot be done. Instead, we load only the core code from expl3-code.tex into the kernel, and then make sure that there is a reload protection that prevents expl3-code.tex from being loaded all over again when expl3.sty is loaded.

The second reason is that both expl3.sty and xparse.sty still offer functionality that, for one reason or the other, was not added to the LaTeX kernel. expl3.sty provides debugging-related load-time options, some of which (undo-recent-deprecations, for example) have no user-level equivalent in the core, so the package is needed. xparse.sty provides the G, l, and u argument types that are not preloaded in the kernel because they are deprecated and kept there only for backwards compatibility.

In both cases, what the packages provide are mostly for compatibility, so in new documents you don't really need to load either (and in fact, using the deprecated argument types from xparse.sty should be discouraged).

Related Question