# Why is \char not expandable?

\char<number> is a TeX primitive that results in the character of ASCII code <number> with category code 12. However, it isn't expandable, unlike it's many cousins \romannumeral, \number, etc.

From my understanding, \char does not look up upper/lowercase/catcode tables, like \uppercase and \lowercase, so I'm confused as to why it unexpandable. (I'm not really sure if this is related at all, but I remember from the top of my head that it's the case for \upper/lowercase)

• Not sure if I'm using the term primitive correctly, I just mean all the control sequences that virgin TeX without anything loaded knows – Planted May 20 at 11:03
• @Mico No, there are a bunch that are expandable, e.g. \expandafter. See also tex.stackexchange.com/questions/467360/… – Henri Menke May 20 at 11:10
• \char accesses a slot in a font and the glyphs at these slots are not necessarily representable in 8-bit encoding in a meaningful way. It's different for Unicode, where all characters are representable in UTF-8 encoding which is why \Uchar in LuaTeX is expandable. – Henri Menke May 20 at 11:14

luatex and xetex provide \Uchar that is expandable

Note that tex has a built in mapping between external character encodings and the internal character codes, and \char access the latter so if \char expanded to a character token and files were written out and read back (for tables of contents etc) then the behaviour would be different to the current non-expandable behaviour as the characters would be re-mapped (incorrectly, most likely)

• I would also mention \char_generate:nn of expl3 that also works with pdftex. – egreg May 20 at 12:57

Only for additional information. You can define expandable \echar{number} by this code in pdftex:

\def\hex#1{\ifcase\numexpr#1\relax 0\or 1\or 2\or 3\or 4%
\or 5\or 6\or 7\or 8\or 9\or a\or b\or c\or d\or e\or f\fi}
\newcount\tmpa  \newcount\tmpb
\def\echar{}
\def\xstring{\expandafter\xstringA\string}  \def\xstringA#1{}
{\endlinechar=-1
\loop
\edef\tmp{\noexpand\xstring\xstring\\^\string^\hex\tmpb\hex\tmpa}
\scantokens\expandafter{\expandafter\edef\expandafter\tmp\expandafter{\tmp}}
\ifnum\tmpb<16 \repeat
}
\edef\echar #1{\noexpand\ifcase\noexpand\numexpr#1\relax\echar\noexpand\fi}


This code creates \echar as macro, roughly speaking:

\def\echar#1{\ifcase#1^^00\or ^^01\or ^^02\or ... \or ^^fe\or ^^ff\fi}


where all tokens between \or have category like after \string.

• yes, the latex format has a command pre-defined essentially like this, \char_generate:nn (the second argument specifying a catcode) – David Carlisle May 27 at 8:55
• It seems to be only academical discussion. Unicode engines have primitives \Uchar and \Ucharcat and there is no reason to use pdftex today. My code above shows that things are more complicated if somebody sticks on pdftex. – wipet May 27 at 12:29
• yes char_generate:nn is \Ucharcat when it is there and a big \ifcase as you show in 8bit tex's – David Carlisle May 27 at 12:53

David Carlisle already has explained why \char should be unexpandable.

However, there are cases in which an expandable version is handy and expl3 has the facility available. Here is a plain TeX version (needs an e-TeX engine such as pdftex, xetex or luatex).

\input expl3-generic

\ExplSyntaxOn

\cs_new:Npn \expchar #1 { \char_generate:nn { #1 } { 12 } }
\cs_new:Npn \xexpchar #1 #2 { \char_generate:nn { #1 } { #2 } }

\ExplSyntaxOff

\edef\test{\expchar{92}}
{\tt\meaning\test}

{\tt\test}

\catcode/=13 \def/{abc}

\xexpchar{47}{13}

\bye


With LaTeX one has a better facility (the category code can be given as an optional argument)

\documentclass{article}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\expchar}{O{12}m}
{
\char_generate:nn { #2 } { #1 }
}
\ExplSyntaxOff

\begin{document}

\ttfamily

\edef\test{\expchar{92}}
\meaning\test

\test

\begingroup
\catcode/=13 \def/{abc}

\edef\test{\expchar[13]{47}}
\meaning\test

\test
\endgroup

\end{document}