Expansion of macros and box contents

I don't understand the following behavior.

Intro

First, here is a simplified version of a macro I am using (which is itself a hacked version of a macro found in gloss.tex). If you have a string MY|STRING with a delimiter in it (in this case, a pipe), then \getmorphs MY|STRING|\\ will split it into its parts MY and STRING. Notice we have to put a pipe at the end of MY|STRING when we pass it as an argument to \getmorphs so that there is always at least one "part delimited by a pipe" (argument #1 in \getmorphs):

\makeatletter
\def\getmorphs#1|#2\\{%
\@getparts(#1,#2,\getmorphs)
}
\def\@getparts(#1,#2,#3){Printed: #1%
\def\more{#2}%
\ifx\more\empty\let\more=\donewords
\expandafter\else\expandafter\let\expandafter\more=#3
\fi
\more#2\\%
}
\gdef\donewords#1\\{}%
\makeatother


That is illustrated here, where \getmorphs prints each part separately:

\getmorphs aaa|bbb|\\% Printed: aaa Printed: bbb (correct)


And it even works if we define a macro which expands to some text with pipes in it, and pass that macro as the argument to \getmorphs. To make it work, we have to use \expandafter so that \testmacro expands before \getmorphs:

\def\testmacro{aaa|bbb}
\getmorphs\testmacro|\\% Printed: aaa|bbb (incorrect)

\expandafter\getmorphs\testmacro|\\% Printed: aaa Printed: bbb (correct)


Problem

In the actual code I am working on, I have an hbox whose contents are aaa|bbb:

\newbox\testbox
\setbox\testbox=\hbox{aaa|bbb}


What I can't figure out is how to pass the contents of that box to \getmorphs. I have tried variations of the sort

\getmorphs\unhbox\testbox|\\
\expandafter\getmorphs\unhbox\testbox|\\


etc., and have even tried defining a scratch macro to expand to \unhbox\testbox and then passed that as the argument to \getmorphs as before:

\def\moretest{\unhbox\testbox}
\expandafter\getmorphs\moretest|\\


Nothing works. Does anyone know how I can access the contents of that hbox and use it as an argument of a macro?

-

What you are trying to do is doomed to fail. There are two reasons: the basic one and the technical one.

• Basic reason: The contents of an \hbox are already typeset and no longer in token form. That is, \hbox{abc}, according to my tests, contains font information for the three letters as well as a kern between the b and the c. Such data is not suitable for absorption as a macro argument; the font character a is not the same as the input character a.

• Technical reason: The only way to get the contents of a box are to \unhbox it. However, all the commands related to boxes are non-expandable: they are instead executable, and are processed by a different mode of TeX's engine. For example, writing \expandafter\getmorphs\unhbox\testbox| is the same as writing \getmorphs\unhbox\testbox| because \unhbox expands to itself and is not "executed". Your attempt to construct \moretest fails because you have simply told \moretest to contain the pair of control words \unhbox\testbox, so that your last example expands to what I wrote just above. It would be equally ineffective to write \edef\moretest{\unhbox\testbox}, for the same reason that \expandafter doesn't work.

The technical reason is based in the reality that all of TeX's facilities for macro processing take place at the "expansion" level, and by the time TeX gets around to "executing" things like \unhbox, all prior macros have already been expanded. There is no way to get "horizontal material" like the contents of a box into a macro, because the macro would no longer exist by the time that material was read.

Going even deeper, you might ask what TeX would even do with something like \tenrm a, which is what \showbox tells me is the first thing in \hbox{abc}. What if the font happened to make an a look like a ( (say, a symbol font)? Should TeX take it to mean a or (, and what character or category code would it have? Once TeX has typeset something, it has moved on to another stage of its existence and can't be brought back.

Probably the best thing for you to do is simply save the thing that goes in your box as a macro or token list and then reuse it as necessary to produce all the results you want from it.

-
Thanks, @Ryan, that was a really informative answer and just what I needed to know. Unfortunately I've been "saving" the things that go into the box in... a different box, so I'll have to do some rethinking of the solution. –  Natalie Oct 13 '11 at 5:29