# How to pass definitions to \AtBeginDocument?

I need to delay execution of a chuk of code to the time when other packages are loaded so I wrap it into \AtBeginDocument:

\AtBeginDocument{%
\def\reserved@a#1#2{%
\edef\reserved@b{#1}%
\edef\reserved@c{#2}%
\ifx\reserved@b\reserved@c
\let\cyrillicencoding\reserved@c
\fi}
\def\cdp@elt#1#2#3#4{%
\reserved@a{#1}{OT2}%
\reserved@a{#1}{LCY}%
\reserved@a{#1}{X2}%
\reserved@a{#1}{T2C}%
\reserved@a{#1}{T2B}%
\reserved@a{#1}{T2A}%
\if@uni@code
\reserved@a{#1}{EU1}%
\reserved@a{#1}{EU2}%
\fi}
\cdp@list
}


This code looks at the list of loaded font encodings (saved in \cdp@list), compare it with predefined list of desired Cyrillic encodings ordered from least preferable to the most preferable (OT2, LCY... EU2) and save the name of selected encoding to the macro \cyrillicencoding. Boolean macro \if@uni@code is evaluated to true if either LuaTeX or XeTeX is running:

\newif\if@uni@code
\ifdefined\luatexversion \@uni@codetrue \else
\ifdefined\XeTeXrevision \@uni@codetrue \fi\fi


It works fine. However it fails if I move some portion of preparatory definitions out of the box. For example,

\def\reserved@a#1#2{%
\edef\reserved@b{#1}%
. . .
\fi}
\AtBeginDocument{\cdp@list}


I guess that macros within moving argument of \AtBeginDocument should be somehow protected or expendafter. Can someone elucidate where my troubles come from? And second question: Is it good practice to delay big chunks of code to at the begin document time?

UPDATE: here is minimal example:

\documentclass{minimal}
\usepackage{mytest}
\usepackage[T2B]{fontenc}
\begin{document}
\verb|cyrillicencoding|={\csname cyrillicencoding\endcsname}
\end{document}


and mytest.sty

\def\reserved@a#1#2{%
\edef\reserved@b{#1}%
\edef\reserved@c{#2}%
\ifx\reserved@b\reserved@c
\let\cyrillicencoding\reserved@c
\fi}
\def\cdp@elt#1#2#3#4{%
\reserved@a{#1}{T2C}%
\reserved@a{#1}{T2B}%
\reserved@a{#1}{T2A}%
}
\AtBeginDocument{\cdp@list}


If the entire content of mytest.sty would be wrapped into \AtBeginDocument, output will be \cyrillicencoding=T2B.

-
Please give a minimal example showing the 'does not work' behaviour. –  Joseph Wright Oct 18 '11 at 5:58
That does not seem to be a minimal example to me. Where does \cdp@list come from? Also, you seem to be defining \resereved@a and expecting it not to change. The \reserved@... macros are kernel only, and you should in general really know what you are doing before you make use of one of them. –  Joseph Wright Oct 18 '11 at 7:17
@Josef, this code is initially borrowed from russianb.ldf from official babel distribution; \cdp@list is defined elsewhere, I guess that this is NFSS macro as it expands to something like {encoding}{family}{series}{shape} (4 args of \cdp@elt#1#2#3#4). –  Igor Kotelnikov Oct 18 '11 at 7:42
@Igor: The minimal class is just a minimal form of a class and not intended to be used for minimal working examples, even if the name makes it look like it. –  Martin Scharrer Oct 18 '11 at 8:05

You should never rely on the meaning of \reserved@a and similar control sequence names that the kernel uses quite often as "scratch macros". So taking out the definition of \reserved@a from \AtBeginDocument is wrong and this is why the version with

\AtBeginDocument{\cdp@list}


For example, with a minimal document, the meaning of \reserved@a that I get when \@begindocumenthook is executed is

> \reserved@a=macro:
->\def \@currenvir {document}\edef \@currenvline {\on@line }\csname document\endcsname .


There's nothing wrong in having big chunks of code in \AtBeginDocument; however you can shorten the token list by saying

\def\@setcyrillicencoding{%
\def\sce@a##1##2{%
\edef\sce@b{##1}%
\edef\sce@c{##2}%
\ifx\sce@b\sce@c
\let\cyrillicencoding\sce@c
\fi}%
\def\cdp@elt##1##2##3##4{%
\sce@a{##1}{OT2}%
\sce@a{##1}{LCY}%
\sce@a{##1}{X2}%
\sce@a{##1}{T2C}%
\sce@a{##1}{T2B}%
\sce@a{##1}{T2A}%
\if@uni@code
\sce@a{##1}{EU1}%
\sce@a{##1}{EU2}%
\fi}%
\cdp@list
}
\AtBeginDocument{\@setcyrillicencoding}
\@onlypreamble\@setcyrillicencoding
\@onlypreamble\sce@a
\@onlypreamble\sce@b
\@onlypreamble\sce@c


The last lines are to free the memory occupied by the macros \@setcyrillicencoding and \sce@x that are useless in the document. The contents of \@begindocumenthook is cleared automatically.

Since \reserved@a is used there, it's not recommendable to redefine it.

-
Thanks, it works! –  Igor Kotelnikov Oct 18 '11 at 14:40

Can someone elucidate where my troubles come from?

You are using reserved *temporary* macros and then don't use them directly. As soon any other LaTeX kernel macro is executed this macros might be overwritten. In other words your definitions won't survive until the \begin{document} and your \cdp@list macros then uses some arbitrary definitions of the temporary macros.

You should use other temporary macros. Should the babel code your are calling really require \reserved@a to be used, you need to make sure that you make your definitions direct before the usage of the \cdp@list macro.

Also your definition of \cdp@elt is changed by fontenc, so of course you would need to do this definition direct before you are going to use it, not inside your package.

Is it good practice to delay big chunks of code to at the begin document time?

I would define everything into one macro and add this macro to the hook only. Every time a hook gets more code all of the old code is copied, which is costly if a lot of packages installed a lot of code. Note that you need to double all # if you place macro definitions into a macro.

-
Minor comment. Maing idea of delaying code here is exactly to allow for fontenc to change \cdp@elt as babel need complete list of encodings loaded throught preamble, both before and after babel. –  Igor Kotelnikov Oct 18 '11 at 11:33