6

Can someone explain to my why \foo and \bar are not the same (in the \ifx sense) in this example:

\documentclass{article}
\begingroup
  \catcode`|=3\relax
  \gdef\abc{|}
\endgroup
\makeatletter
\newcommand\foobar{
  \begingroup
    \catcode`|=3\relax
    \def\abc{|}
    \@foobar
}
\newcommand\@foobar[1]{
  \xdef\foo{#1}
  \endgroup
}
\edef\bar{\abc}
\foobar{\abc}

\begin{document}
foo means ``\meaning\foo'' and bar means ``\meaning\bar'', but the ``meanings'' are
\ifx\foo\bar
  same
\else
  different
\fi
\end{document}

I included the \@foobar because I read somewhere that the catcode had to be changed before reading the macro parameter (I don't think it applies here, but I have no idea what I am doing).

The global definition of \abc (the one defined with \gdef) is | with catcode 3. I would like the local definition of \abc (the one defined with \def) to also be | with catcode 3. In my example the local \abc is | with catcode 12. Ultimately I would like to have \foobar{\abc} expand to | with catcode 3 without having \abc defined golbally.

StrongBad
  • 20,495

3 Answers3

8

The problem lies here:

\newcommand\foobar{
  \begingroup
    \catcode`|=3\relax
    \def\abc{|}
    \@foobar
}

The \def\abc{|} is read by \newcommand and its catcodes are fixed then. The \catcode|=3\relaxis executed when the\foobar` macro is used not when it is defined.

You can use the following instead:

\begingroup
\newcommand\foobar{}% to get the name check 
\catcode`\|=3\relax
\gdef\foobar{%
  \begingroup
    \catcode`\|=3\relax
    \def\abc{|}%
    \@foobar
}
\endgroup

This changes the catcode of | to 3 also for the definition. You onlt need to use \@foobar if the user should be allowed to add | with catcode 3 inside the argument. Otherwise you simply let \foobar read the argument and use \xdef\foo{#1} inside \foobar directly. Then you don't need the second, inner\catcode\|=3\relax` line as well.

Also, you should place % at lines ending with { or } because otherwise the source code line breaks will be taken as a space which are inserted in the document.

Martin Scharrer
  • 262,582
  • I think there is an extra \begingroup in the definition of \foobar (left over from my awful example). I am not so confident to actually edit your answer. – StrongBad Mar 08 '12 at 17:49
  • @DanielE.Shub: No, I don't think so. The closing \endgroup is inside \@foobar. Keep in mind that the outer grouping commands are executed during the definition but the inner ones during the usage of the macro. – Martin Scharrer Mar 08 '12 at 18:22
4

I have no idea what you want to achieve. But the catcode of an input is assigned at the moment when TeX reads the input the first time. When the definition body of foobar is read the catcode of | is "other" and so your \foobar will always define "\abc = | with catcode other", regardless of the catcode value when you actually execute \foobar.

If you want to change the catcode of an input you can do it e.g. by writing it to an external file and then reinput it or by using \scantokens.

Ulrike Fischer
  • 327,261
4

They are different because one holds a math-shift character and the other holds a punctuation character (catcodes 3 and 12) you can see this if you typeset

foo \foo 1*2*3 \foo

bar \bar 1*2*3 \bar

You can locally define \abc to be a \catcode 3 | with various idioms for example this one is used all over the place (usually with ~ to get an active character rather than $) for example the definition of \verb in latex.ltx.

\begingroup\lccode`$=`\|\lowercase{\endgroup\def\abc{$}}

defines \abc to be a math-shift | without any global definition.

David Carlisle
  • 757,742