9

In this MWE I define an environment where a particular letter is active with some meaning once with the \lowercase trick and once with \gdef:

\documentclass{article}

\begingroup
\catcode`\A=\active
\gdefA#1{(#1)}
\endgroup
\newenvironment{foo}{\catcode`\A=\active }{}

\begingroup
\lccode`\~=`\B
\lowercase{\endgroup\def~}#1{(#1)}
\newenvironment{baz}{\catcode`\B=\active }{}

\begin{document}

\begin{foo}foo Abaz A{bar}\end{foo}

\begin{baz}foo Bbaz B{bar}\end{baz}

\end{document}

and both environments yield of course the same output:

enter image description here

I wonder if there is some reason to prefer one way instead of the other.

10

Firstly, the \lowercase trick doesn't require the assignment to be global, so whatever definition you change, it will be restricted to the current scope, which is usually what you want (if it's not, you can use \gdef in the \lowercase code too).

But probably the main advantage is that the \lowercase trick allows you to “generate” the active character on-the-fly, while with the \gdef approach the active character has to be typed directly (actually, in the \lowercase approach the active character is typed directly, but it's the ~, which is already active).

Suppose your environment takes an argument, which is the character to be made active. With the naïve \gdef approach it's not possible:

\documentclass{article}

\newenvironment{baz}[1]{%
  \begingroup
    \lccode`\~=`#1
    \lowercase{%
  \endgroup\def~}##1{(##1)}%
  \catcode`#1=\active
}{}

\begin{document}

\begin{baz}{B}foo Bbaz B{bar}\end{baz}

{\catcode`\B=\active \show B}

\end{document}

and \show B shows that the definition of “active-char-B” didn't change globally:

> B=undefined.
l.16 {\catcode`\B=\active \show B
                                 }
?

You can use yet another trick to avoid the \gdef in the first approach. If you do, assuming \@firstofone has its usual LaTeX meaning (\@firstofone=\long macro:#1->#1):

\makeatletter
\begingroup
  \catcode`\A=\active
  \@firstofone{%
\endgroup
\defA}#1{(#1)}

then the argument of \@firstofone, \endgroup\defA will be tokenized before the \endgroup is processed, so \defA will still be \def <active-char-A> even after the \endgroup, so the change will be limited to the current scope. However if you want to make an environment with that, you still can't automatically generate the active characters, so you need to “activate” each character one-by-one (and ensure that they are active at the time you define the environment).


Here's one example of how the \lowercase approach is better to locally change the meaning of a character while still preserving its meaning outside the scope of your macro/environment. In this example I use the fact that French babel makes ! an active character. Consider this example using the \lowercase trick:

\documentclass{article}
\usepackage[french]{babel}
\newenvironment{baz}[1]{%
  \begingroup
    \lccode`\~=`#1
    \lowercase{%
  \endgroup\def~}##1{(##1)}%
  \catcode`#1=\active
}{}
\begin{document}
\show! % > !=macro:->\active@prefix !\active@char!
\begin{baz}{!}foo !baz !{bar}\end{baz}
\show! % > !=macro:->\active@prefix !\active@char!
\end{document}

and this one using a directly typed !:

\documentclass{article}
\usepackage[french]{babel}
\newenvironment{baz}[1]{\catcode`!=\active}{}
\begin{document}
\show! % > !=macro:->\active@prefix !\active@char!
\makeatletter
\begingroup
  \catcode`\!=\active
  \@firstofone{%
\endgroup
\def!}#1{(#1)}
\makeatother
\begin{baz}{!}foo !baz !{bar}\end{baz}
\show! % > !=macro:#1->(#1)
\end{document}

They are much the same code. They key differences are:

1) In the \lowercase version the definition can go in the preamble, because it dynamically (abusing the meaning of the word) generates the active ! character without the need of setting it up first. In the \gdef version (in which I didn't use \gdef, but just to keep the naming in your question) the setup of the ! character to be used needs to go after \begin{document}, otherwise your definition is overridden by babel.

and 2) You lose babel's definition of ! because you have to globally define the meaning of the active character ! (or whatever code which happens to have an active meaning and you use in your environment). The \lowercase version allows you to keep this definition local so you do not need to worry about that.

Overall, there is little reason to prefer the “\gdef approach” over the \lowercase. It's harder to set up, it's possibly problematic when interacting with other packages, and doesn't allow you to programatically change characters.

  • Great! I guess the bottom line is that for some macro/environment which has to be defined globally anyway they are equivalent, while \lowercase is necessary for local definitions. – campa Oct 25 '19 at 11:18
  • @campa The fact that the macro/environment needs to be locally does not interfere on the fact that you usually don't want to change the active definition of a character globally (unless you do, of course :-). For example, if you do that you might clash with babel's definitions. What remains local in the \lowercase approach is the definition of the active character. Note that the ´\show B` shows undefined instead of B=macro:#1->(#1). I'll add another example with babel. – Phelype Oleinik Oct 25 '19 at 11:25
  • @campa I added another example – Phelype Oleinik Oct 25 '19 at 11:50
  • Excellent and great also for me! – Sebastiano Nov 5 '19 at 12:51

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.