Can't generate a tikz matrix, using expl3

Suppose, I want to generate a matrix of nodes:

\documentclass{article}
\usepackage{expl3}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
\matrix
[
row  sep=2mm,
] (matr)
{
\node[draw] (1) {1};\\
\node[draw] (2) {2};\\
\node[draw] (3) {3};\\
};
\end{tikzpicture}
\end{document}


I tried to do it, using expl3 for loop:

\documentclass{article}
\usepackage{expl3}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
\matrix
[
row  sep=2mm,
] (matr)
{
\ExplSyntaxOn
\tl_new:N \l__text_tl
\int_step_inline:nnnn { 1 } { 1 } { 3 }
{
\tl_put_right:Nn \l__text_tl {\node[draw] (#1) {#1};\\}
}
\l__text_tl
\ExplSyntaxOff
};
\end{tikzpicture}
\end{document}


The compiler fails with message:

! Missing } inserted. <inserted text>
}
l.21 \end{tikzpicture}

-

You can not change catcodes in the argument of another command, so

\documentclass{article}
\usepackage{expl3}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l__text_tl
\int_step_inline:nnnn { 1 } { 1 } { 3 }
{
\tl_put_right:Nn \l__text_tl {\node[draw] (#1) {#1};\\}
}

\let\foo\l__text_tl
\ExplSyntaxOff

\begin{tikzpicture}
\matrix
[
row  sep=2mm,
] (matr)
{
\foo
};
\end{tikzpicture}
\end{document}


This is a basic restriction of the way TeX tokenises file characters, \verb, \makeatletter, \ExplSyntaxOn all have the restriction that they must be used at the top level.

-

The main point to note really is that the expl3 language was never intended for document level usage just like the internals of LaTeX2e (having @ in their names) are not supposed to show up there. Instead those languages have been developed to support package development.

Thus within a LaTeX2e package the conventions of LaTeX2e are automatically set up (which is basically @ being a letter) and within a LaTeX3 package the conventions for LaTeX3 are automatically enabled.

However, sometimes it is necessary to add/update code in the preamble of a document and recognizing this, LaTeX2e offers \makeatletter and \makeatother and LaTeX3/expl3 offers \ExplSyntaxOn and \ExplSyntaxOff. But those are for preamble usage and in general it is better to put such code into a package, which could then be reused.

So you could think of providing a command that does the necessary work for you, e.g., \boxednumbers which does everything including the matrix command, e.g.,

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usepackage{xparse}
\ExplSyntaxOn

\tl_new:N \l__text_tl

\NewDocumentCommand\boxednumbers{ O{2mm} m }
{
\tl_clear:N\l__text_tl
\int_step_inline:nnnn { 1 } { 1 } { #2 }
{   \tl_put_right:Nn \l__text_tl {\node[draw] (##1) {##1};  \\ } }
\matrix [row~  sep=#1] (matr)
{
\l__text_tl
};
}
\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}   \boxednumbers{5};       \end{tikzpicture}
\begin{tikzpicture}   \boxednumbers[5mm]{3};  \end{tikzpicture}

\end{document}


There is one important point to note here:

• tikz was designed under 2e conditions and it doesn't know about expl3 conventions.

So executing tikz commands that do parsing in the middle of expl3 code is likely to cause trouble, which is why we can't simply execute \node in that loop, but instead build a line of code to be executed later. For the same reason I had to say row~ sep instead of row sep as the normal space vanishes within expl3 code. So in summary the mix and match of 2e code with expl3 is a little tricky in places.

-