3

How to reliably obtain a control sequence token which is undefined in the current scope?

E.g., is there a sequence of tokens ⟨stuff⟩ with which you can do

\begingroup\expandafter\endgroup\expandafter\dosomething\csname ⟨stuff⟩\endcsname

so that

  • TeX won't deliver any error-message while producing the control sequence token from the \csname..\endcsname-expression and
  • the resulting control sequence token behind \dosomething in any case is undefined after processing \endgroup?

I could use this for reliably letting another control sequence token equal to something that is undefined.

By now I do s.th. like \let\token=\UndeFineD and hope for no piece of third-party-code defining \UndeFineD before the \let-assignment is performed.

Another approach could be a loop for constructing names of control sequence tokens until one is found where a test like

\DeclareRobustCommand\CheckWhetherDefined[1]{%
  \begingroup
  \expandafter\ifx\csname#1\endcsname\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \expandafter\endgroup\expandafter\ifx\csname#1\endcsname\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  }{\endgroup\@firstoftwo}%
}%

or like

\DeclareRobustCommand\CheckWhetherDefined[1]{%
  \ifcsname#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%

does yield \@secondoftwo.

But I wonder if there is something more clever.

Perhaps an edge case of a \csname..\endcsname-expression - something of similar "edgeiness" to the scenario of using "frozen-\relax" in situations where you need a token which definitely is not an explicit character-token and which definitely never is defined in terms of \outer.


Please notice that the focus of the question is not on methods for testing whether a control sequence token is defined/undefined.

I ask for the best way of obtaining a control sequence token that is undefined in the current scope.

In this context, a test for "definedness/undefinedness" would only be a means to an end, e.g., if one chooses the path of creating tokens until one is created that is not defined.


"Academic question": is there an easily implementable method in TeX to enumerate all possible control sequence names?

8
  • 1
    While I find the question interesting, I don't see the practical relevance. Isn't the kernel relying on \undefined being undefined? If it isn't, it would break right along your code. More generally, LaTeX heavily relies on conventions anyways, like that \relax is the TeX primitive and not something else (or undefined). Relying on \undeifned isn't really different, is it?
    – schtandard
    Feb 13 at 11:44
  • 1
    It seems to me in latex \@undefined plays that role, though there's no warranty. (\undefined is the one used by plaintex, and some packages uses its own ones, for example etoolbox uses \etb@undefined in \undef and tikz-pgf uses \pgfutil@undefined). Feb 13 at 11:47
  • 1
    see the definition of \@ifundefined in recent released which use \ifcsname Feb 13 at 11:49
  • 1
    although if you are being passed a token rather than the character tokens representing the name, just do \ifx\token\@undefind Feb 13 at 12:13
  • What you are asking for is fundamentally impossible because TeX can redefine its own syntax, so even if there was a primitive (or combination of primitives) that would result in an undefined control sequence, there is no way to prevent the surrounding code from redefining those primitives to break this behavior. As already said by the other comments TeX macro code heavily relies on convention, so best go for something like \undefined or \@undefined. Anybody defining any of those is clearly asking for trouble. Feb 13 at 13:29

3 Answers 3

4

The following is similar in spirit to Henri's answer, but builds the control sequence name predictably in a loop instead of using random numbers.

This should work in every engine with e-TeX.

\begingroup
\catcode`\@=11
\catcode`\^^@=12
\unexpanded{\endgroup
\protected\def\provideundefinedcsto#1%
  {%
    \begingroup
      \expandafter
    \endgroup
    \expandafter#1\csname\provideundefinedcsto@{^^@}\endcsname
  }
\def\provideundefinedcsto@#1%
  {%
    \ifcsname #1\endcsname\expandafter\@secondoftwo\fi
    \@gobble{\provideundefinedcsto@{#1^^@}}^^@%
  }
\long\def\@secondoftwo#1#2{#2}
\long\def\@gobble#1{}
}

\provideundefinedcsto\show
\bye
3
4

You could random-sample control sequence names until you find one that has not been defined

pdfTeX-only

\catcode`@=11

\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}

\long\def\@ifcsname#1{%
  \ifcsname #1\endcsname
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\long\def\@uniquecsname#1{%
  \@ifcsname{#1}%
    {\expandafter\@uniquecsname\expandafter{\number\pdfuniformdeviate\maxdimen}}%
    {#1}%
}

\def\uniquecsname{\expandafter\@uniquecsname\expandafter{\number\pdfuniformdeviate\maxdimen}}

\begingroup\expandafter\endgroup\expandafter\meaning\csname\uniquecsname\endcsname

\bye
2

I don't think you can avoid e-TeX, in particular \ifcsname. If your aim is to really undefine some token, you can do a loop with integers, which will avoid long strings.

\def\undefine#1{%
  \begingroup
  \count255=0
  \buildundefined
  \expandafter\endgroup\expandafter\let\expandafter#1\csname\the\count255\endcsname
}
\def\buildundefined{%
  \immediate\write20{Testing \the\count255}% for debugging
  \ifcsname\the\count255\endcsname
    \advance\count255 by 1
    \expandafter\buildundefined
  \fi
}

% just for testing
\def\token{token}
\def\0{}
\def\1{}
\def\2{}

\immediate\write20{\noexpand\token is \meaning\token}

\undefine\token

\immediate\write20{\noexpand\token is \meaning\token}

\immediate\write20{\meaning\3}

\bye

The console output is

\token is macro:->token
Testing 0
Testing 1
Testing 2
Testing 3
\token is undefined
undefined

and the last line shows that the control sequence used for the \let, in this case \3, is still undefined at the end of the job.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.