0

I would like to create a command that checks whether an expression is fully expandable, and crashes if not (ideally printing an error message). I would like to do that without a specific TeX engine in mind. I think it's related to this question Check if macro is fully expandable, but the provided answer requires LuaTeX.


Test code

A test code would look like this:

\documentclass[preview = true, varwidth = true]{standalone}
\usepackage{xparse}
\usepackage{xstring}

\NewDocumentCommand{\checkexpandability}{m}{
    % CODE HERE
}

\newcommand{\expandable}[1]{#1}
\newcommand{\notexpandable}[1]{%
    \edef\myvariable{\expandable{#1}}%
    \myvariable%
}

\begin{document}
\checkexpandability{\expandable{test}} % Should be OK
\checkexpandability{\notexpandable{test}} % Should CRASH
\checkexpandability{\IfBeginWith{string}{str}{true}{false}} % Should CRASH
\end{document}

In case it's too complicated

If it's not doable, then I am ok to modify the command signature to include a parameter that is what the command should expand to:

\begin{document}
\checkexpandability{\expandable{test}}{test} % Should be OK
\checkexpandability{\notexpandable{test}}{test} % Should CRASH
\checkexpandability{\IfBeginWith{string}{str}{true}{false}}{true} % Should CRASH
\end{document}

Comment on expandability

Since the definition of fully expandable is not as clear as one could think (see comment below), the context of this question is that I'm just trying to create something that helps me debug some code. I'm ok to restrain the question to this specific behavior : whether the macro would work in the context macros like the \color command:

\documentclass[preview = true, varwidth = true]{standalone}
\usepackage{xcolor}

\newcommand{\expandable}[1]{#1}
\newcommand{\notexpandable}[1]{%
    \edef\myvariable{\expandable{#1}}%
    \myvariable%
}
    
\begin{document}
\color{\expandable{blue}} % OK
\color{\notexpandable{red}} % CRASHES
X
\end{document}

Basically, the \color command does the kind of job I'm looking for, it's just that I would like to call it \checkexpandability, be a little more generic, and print a nice error message.

9
  • it is rather unclear what you mean by expandable. See also tex.stackexchange.com/a/66168/2388 Feb 3 at 23:39
  • @UlrikeFischer I added a comment at the end of the question
    – Vincent
    Feb 3 at 23:52
  • what you want to do is not really possible, also you need to define what you mean by "expandable" \relax for example is safe in an \edef but not in \color. If you mean a command that expands to something legal in the current context, then there is no general definition. Feb 3 at 23:55
  • there is no context "like" the \color command, only the color command. The argument of \color has to expand to a valid color name otherwise you get an error. There is no sense in which it "checks for expandability" it just expects a color name (after expansion) Feb 3 at 23:57
  • \color{\expandable{123}} would error too. Feb 4 at 0:03

2 Answers 2

4

I think the basic misunderstanding is

Basically, the \color command does the kind of job I'm looking for,

The \color command does no checks of the type requested, it simply expects that after expansion the argument is a defined color name. If the expansion fails you get a low level error or if it expands to an undefined color you get a specific error message, but no part of the processing is generic or applies to a command other than commands expecting colors.

The one version that could be implemented is the version with an expected expansion as that is simply asking if the two arguments are equal after expansion. The L3 programming layer has several variants of that or you could use the ifthen package and

\ifthenelse{\equal{\expandable{test}}{test}}{yes}{no}

which will return yes if the arguments expand to the same thing, no if they do not, or give a low level error if the argument is not safe in an expansion context (which is what is usually meant by "is not expandable")

3

To debug your code, I'd just use \typeout.

\documentclass[preview = true, varwidth = true]{standalone}
\usepackage{xcolor}

\newcommand{\expandable}[1]{#1}
\newcommand{\notexpandable}[1]{%
    \edef\myvariable{\expandable{#1}}%
    \myvariable%
}
    
\begin{document}
\typeout{\expandable{blue}} % OK, print "blue"
\typeout{\notexpandable{red}} % CRASHES
X
\end{document}

The point is that \typeout will fully expand its argument, then print whatever the fully expanded result is on the terminal --- so you can just take a look at the terminal.

For the first case it prints blue, so everything is fine. For the second case, it crashes.


Of course, there are two problems with the approach above.

  • Even if \expandable{blue} is fully expandable (whatever it means), it may not be the case that \color is guaranteed to fully expand its argument before interpreting the result as a color. (I guess by Hyrum's law it would practically be to avoid breaking "existing packages", however.)

    So, if you want to be extra sure, it's better to expand it in advance using e.g. \ExpandArgs.

  • The information on category code, as well as any special character lurking in the code (e.g. space versus tab), is lost.

    In practice this wouldn't matter much, but sometimes it does. (e.g. when you try to debug some package that attempts to capture the environment body verbatim)

    If that's the case, consider trying out my package. (the code is a mess right now, but well it works, and there are packages with worse source code out there)

2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .