Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

keyval package and expansion

15 views
Skip to first unread message

Hendri Adriaens

unread,
Dec 12, 2003, 9:16:49 AM12/12/03
to
Hi,

I am using the keyval package and observe some problem with expansions. The
minimal example is posted below:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{article}
\usepackage{keyval}

\makeatletter
\define@key{mykeys}{probber}{\def\@probber{#1}}
\def\prob{\@ifnextchar[\@prob{\@prob[]}}
\def\@prob[#1]#2{%
\setkeys{mykeys}{#1}%
\def\@test1{\@probber}%
\show\@test1%
\edef\@test2{\@probber}%
\show\@test2}
\makeatother

\begin{document}
some text\\
\prob[probber=NoUmlaut]{test1}
\prob[probber=\"Umlaut]{test2}
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Part of the log is:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> \@test=macro:
1->\@probber .
\@prob ...1}\def \@test 1{\@probber }\show \@test
1\edef \@test 2{\@probber
...
l.18 \prob[probber=NoUmlaut]{test1}

?
> \@test=macro:
2->NoUmlaut.
\@prob ...1\edef \@test 2{\@probber }\show \@test
2
l.18 \prob[probber=NoUmlaut]{test1}

?
> \@test=macro:
1->\@probber .
\@prob ...1}\def \@test 1{\@probber }\show \@test
1\edef \@test 2{\@probber
...
l.19 \prob[probber=\"Umlaut]{test1}

?
> \@test=macro:
2->\unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa \hbox
{U\g
lobal \mathchardef \accent@spacefactor \spacefactor }\accent 127 U\egroup
\spac
efactor \accent@spacefactor mlaut.
\@prob ...1\edef \@test 2{\@probber }\show \@test
2
l.19 \prob[probber=\"Umlaut]{test1}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The problem: when doing \def (no expansion), the key does not get expanded,
we end up with some macro, but I want to have the 'value' of that macro.

So I expand it, but then I am stuck with a very ugly thing (which in the
more complex application really doesn't work) in case we use commands for
the keyval option. Even when putting [probber=\protect{\"Umlaut}] or
[probber=\noexpand{\"Umlaut}] the argument still gets expanded two times.

How can I stop this? I would like to see (in the current example) that
\@test2 just gets the value \"Umlaut.

Any help is appreciated. Best regards,
-Hendri Adriaens.


Hendri Adriaens

unread,
Dec 12, 2003, 9:45:06 AM12/12/03
to
Hi,

I found that in the minimal example the following works:
\define@key{mykeys}{probber}{\def\@probber{\string#1}}

But unfortunately, this does not work in the more complicated application. I
will try to distill a new minimal example or find the difference that makes
this solution not work in the real application.

Thanks anyway,
-Hendri Adriaens.


Stefan Ulrich

unread,
Dec 12, 2003, 10:35:14 AM12/12/03
to
Hendri Adriaens <spotje38R...@hotmail.com> writes:

> I am using the keyval package and observe some problem with expansions. The
> minimal example is posted below:

> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> \documentclass{article}
> \usepackage{keyval}

> \makeatletter
> \define@key{mykeys}{probber}{\def\@probber{#1}}
> \def\prob{\@ifnextchar[\@prob{\@prob[]}}
> \def\@prob[#1]#2{%
> \setkeys{mykeys}{#1}%
> \def\@test1{\@probber}%
> \show\@test1%

FWIW, you can't have digits in command names ...

> \edef\@test2{\@probber}%
> \show\@test2}

In LaTeX, always use \protected@edef, unless you know what
you're doing.

> So I expand it, but then I am stuck with a very ugly thing (which in the
> more complex application really doesn't work) in case we use commands for
> the keyval option. Even when putting [probber=\protect{\"Umlaut}] or

This protects the `{', which is probably not what you want.

--
Stefan Ulrich

Hendri Adriaens

unread,
Dec 12, 2003, 11:31:58 AM12/12/03
to
> FWIW, you can't have digits in command names ...

True.

> In LaTeX, always use \protected@edef, unless you know what
> you're doing.

OK, thanks for the remark.

> This protects the `{', which is probably not what you want.

Indeed. I am still trying to figure out how my more complicated application
differs from the minimal example. When using some \show's in the source, I
found that everything is running exactly in line with the minimal example
until I start to expand the key. The minimal example (when using \string#1
in the definition) then gives the desired result, but my application expands
the argument twice while the argument is exactly the same in both cases. I
must be overlooking something...

Anyway, thanks for your reaction. I will let you know when I found the
error.

Best regards,
-Hendri.


Heiko Oberdiek

unread,
Dec 12, 2003, 10:15:37 AM12/12/03
to
"Hendri Adriaens" <spotje38R...@hotmail.com> wrote:

> Hi,
>
> I am using the keyval package and observe some problem with expansions. The
> minimal example is posted below:
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> \documentclass{article}
> \usepackage{keyval}
>
> \makeatletter
> \define@key{mykeys}{probber}{\def\@probber{#1}}
> \def\prob{\@ifnextchar[\@prob{\@prob[]}}
> \def\@prob[#1]#2{%
> \setkeys{mykeys}{#1}%
> \def\@test1{\@probber}%

You know, "\@test1" is not a macro, this are two tokens "\@test" and
the digit "1".

> \show\@test1%
> \edef\@test2{\@probber}%
> \show\@test2}
> \makeatother
>
> \begin{document}
> some text\\
> \prob[probber=NoUmlaut]{test1}
> \prob[probber=\"Umlaut]{test2}

> l.19 \prob[probber=\"Umlaut]{test1}


>
> ?
> > \@test=macro:
> 2->\unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa \hbox
> {U\g
> lobal \mathchardef \accent@spacefactor \spacefactor }\accent 127 U\egroup
> \spac
> efactor \accent@spacefactor mlaut.
> \@prob ...1\edef \@test 2{\@probber }\show \@test
> 2
> l.19 \prob[probber=\"Umlaut]{test1}
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> The problem: when doing \def (no expansion), the key does not get expanded,
> we end up with some macro, but I want to have the 'value' of that macro.
>
> So I expand it, but then I am stuck with a very ugly thing (which in the
> more complex application really doesn't work) in case we use commands for
> the keyval option. Even when putting [probber=\protect{\"Umlaut}] or
> [probber=\noexpand{\"Umlaut}] the argument still gets expanded two times.

You are protecting/noexpanding the curly brace. \protect and \noexpand
does affect the next *token* only, but not a whole group.

==> \noexpand\"Umlaut

Probably better is the use of the LaTeX interface:

...
\protected@edef\@testii{\@probber}%
\show\@testii
...

\prob[probber=\"Umlaut]

Then you will need \protect for fragile commands only.

Yours sincerely
Heiko <ober...@uni-freiburg.de>

Hendri Adriaens

unread,
Dec 12, 2003, 12:47:37 PM12/12/03
to
Hi all,

I found a new minimal example that actually demonstrates the problem
exactly:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{article}
\usepackage{keyval}

\makeatletter
\define@key{mykeys}{probber}{\def\@probber{\string#1}}


\def\prob{\@ifnextchar[\@prob{\@prob[]}}
\def\@prob[#1]#2{%

\let\@probber\undefined%
\setkeys{mykeys}{#1}\show\@probber%
\@@prob{\@probber}
}
\def\@@prob#1{%
\def\@testa{#1}%
\show\@testa%
\edef\@testb{#1}%
\show\@testb}%
\makeatother

\begin{document}
some text\\
\prob[probber=NoUmlaut]{test1}
\prob[probber=\"Umlaut]{test2}

\prob[probber=Umla\"ut]{test3}
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The partial log shows:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> \@probber=macro:
->\string NoUmlaut.
\@prob ...ed \setkeys {mykeys}{#1}\show \@probber
\@@prob {\@probber }
l.21 \prob[probber=NoUmlaut]{test1}

?
> \@testa=macro:
->\@probber .
\@@prob #1->\def \@testa {#1}\show \@testa
\edef \@testb {#1}\show \@testb
l.21 \prob[probber=NoUmlaut]{test1}

?
> \@testb=macro:
->NoUmlaut.
\@@prob ...@testa \edef \@testb {#1}\show \@testb

l.21 \prob[probber=NoUmlaut]{test1}

?
> \@probber=macro:
->\string \"Umlaut.
\@prob ...ed \setkeys {mykeys}{#1}\show \@probber
\@@prob {\@probber }
l.22 \prob[probber=\"Umlaut]{test2}

?
> \@testa=macro:
->\@probber .
\@@prob #1->\def \@testa {#1}\show \@testa
\edef \@testb {#1}\show \@testb
l.22 \prob[probber=\"Umlaut]{test2}

?
> \@testb=macro:
->\"Umlaut.
\@@prob ...@testa \edef \@testb {#1}\show \@testb

l.22 \prob[probber=\"Umlaut]{test2}

?
> \@probber=macro:
->\string Umla\"ut.
\@prob ...ed \setkeys {mykeys}{#1}\show \@probber
\@@prob {\@probber }
l.23 \prob[probber=Umla\"ut]{test3}

?
> \@testa=macro:
->\@probber .
\@@prob #1->\def \@testa {#1}\show \@testa
\edef \@testb {#1}\show \@testb
l.23 \prob[probber=Umla\"ut]{test3}

?
> \@testb=macro:
->Umla\unhbox \voidb@x \bgroup \let \unhbox \voidb@x \setbox \@tempboxa
\hbox {
u\global \mathchardef \accent@spacefactor \spacefactor }\accent 127 u\egroup
\s
pacefactor \accent@spacefactor t.
\@@prob ...@testa \edef \@testb {#1}\show \@testb

l.23 \prob[probber=Umla\"ut]{test3}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

If you look closely at the log, you will see that the 2nd case (\"Umlaut)
doesn't get expanded twice when using \edef, but the 3rd case (Umla\"ut)
does get expanded twice!

If anyone has an idea how to solve this, this would be really welcome! This
is such strange behavior that I really don't know where to look for a
solution.

Thanks a lot in advance for any helpful hints or solutions.

Best regards,
-Hendri Adriaens.


Hendri Adriaens

unread,
Dec 12, 2003, 1:04:15 PM12/12/03
to
Dear Heiko,

> Probably better is the use of the LaTeX interface:
>
> ...
> \protected@edef\@testii{\@probber}%
> \show\@testii

That indeed works locally. But my application is a bit more complicated. I
need to 'remember' this macro until the program returns to the definition
the next time. So I did:

\protected@xdef\@testii{\@probber}%

And I expected that to work. But strangely enough, right after the
definition, the macro is OK, but when I return to the definition and check
the macro, it has still expanded for some strange reason. Let me remark,
that I am not doing anything to that macro untill it returns. Then I test:
\if\@probber\@empty\else\show\@probber%

and now the show reveals an expanded macro.

I don't understand this. BTW, the new minimal example that I posted at the
same time you posted the reply works with your solution. I expected that
making the definition global would not cause any problems, that is why I did
not include that. But it actually does...

And I have to admit that I am still learning. I didn't know
\protected@edef...

Thanks for the help already, best regards,
-Hendri Adriaens.


Hendri Adriaens

unread,
Dec 12, 2003, 1:05:45 PM12/12/03
to
Sorry, of course I didn't do

\if\@probber\@empty\else\show\@probber%

but
\if\@testii\@empty\else\show\@testii%

(Names between minimal example and application got a bit mixed)

-Hendri.


Hendri Adriaens

unread,
Dec 12, 2003, 1:17:43 PM12/12/03
to
> and now the show reveals an expanded macro.

OK, I solved that, but now I get a whole range of new, never seen before
errors like use of \begin@slide doesn't match its definition.

I will try to figure out what has been messed up by using \protected@xdef...

Thanks again a lot for all replies.

Best,
-Hendri.


Hendri Adriaens

unread,
Dec 12, 2003, 1:53:34 PM12/12/03
to
Here's a minimal example again.

%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{article}
\usepackage{keyval}

\makeatletter
\define@key{mykeys}{probber}{\def\@probber{\string#1}}%


\def\prob{\@ifnextchar[\@prob{\@prob[]}}
\def\@prob[#1]#2{%

\let\@probber\undefined%
\setkeys{mykeys}{#1}%


\@@prob{\@probber}
}
\def\@@prob#1{%

\protected@edef\@testii{\@probber}%
\show\@testii%
}%
\makeatother

\begin{document}
some text\\
%\prob[probber=NoUmlaut]{test1}
%\prob[probber=\"Umlaut]{test2}
\prob[probber=Umla\"ut]{test3}
\prob[probber=]{test4}
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%

And the log:

%%%%%%%%%%%%%%%%%%%%%%%%
> \@testii=macro:
->Umla\"ut.
\@@prob ...ef \@testii {\@probber }\show \@testii

l.22 \prob[probber=Umla\"ut]{test3}

?
! Argument of \@firstofone has an extra }.
<inserted text>
\par
l.24 \end{document}

?
! Use of \@prob doesn't match its definition.
\@checkend #1->\def \reserved@a {
#1}\ifx \reserved@a \@currenvir \else
\@bad...
l.24 \end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The problem, you can see it, is caused when specifying an empty string as
argument. In my application, I need to identify between three cases:
argument is a string of at least 1 character; argument is empty string (but
specified, see above); argument is not specified (hence due to keyval
package undefined).

I used to test (when using \define@key{mykeys}{probber}{\def\@probber{#1}}
\ifx\@probber\@empty
for the second case, but that does not work anymore since in that case,
\@probber has the value '\string ' (including the space) due to
\define@key{mykeys}{probber}{\def\@probber{\string#1}}

How can I test now if \@probber is indeed exactly equal to that string (and
hence that the argument was empty)?

Thanks, best regards,
-Hendri.


Heiko Oberdiek

unread,
Dec 12, 2003, 3:57:13 PM12/12/03
to
"Hendri Adriaens" <spotje38R...@hotmail.com> wrote:

> Here's a minimal example again.
> %%%%%%%%%%%%%%%%%%%%%%%
> \documentclass{article}
> \usepackage{keyval}
>
> \makeatletter
> \define@key{mykeys}{probber}{\def\@probber{\string#1}}%

Bad idea to use \string:
* command names are not protected, they are converted into
letter tokens with catcode 12.
* What happens, if #1 is empty?

\define@key{mykeys}{probber}{%
\def\@probber{#1}%
}

> \def\prob{\@ifnextchar[\@prob{\@prob[]}}
> \def\@prob[#1]#2{%
> \let\@probber\undefined%

The line before the "%" is not necessary.

> \setkeys{mykeys}{#1}%
> \@@prob{\@probber}

The line before "%" is missing to comment the line end.

> }
> \def\@@prob#1{%
> \protected@edef\@testii{\@probber}%

#1 is thrown away, perhaps you wanted:
\protected@edef\@testii{#1}%

> \show\@testii%
> }%
> \makeatother

With indenting the code would be much more better readable.

Yours sincerely
Heiko <ober...@uni-freiburg.de>

Hendri Adriaens

unread,
Dec 12, 2003, 4:56:29 PM12/12/03
to
Dear Heiko,

> Bad idea to use \string:
> * command names are not protected, they are converted into
> letter tokens with catcode 12.
> * What happens, if #1 is empty?

Indeed, that was my question. What happens when #1 is empty.

> The line before the "%" is not necessary.

It is in my application since keyval does not throw keys away
when they are not used. When repeatively executing definitions,
this will cause problems.

> \protected@edef\@testii{#1}%

Indeed.

Actually, the \string was proposed by the keyval package docs
and I needed it in a previous situation. The current setup with
\protected@xdef (thanks again!) does not need that indeed.
I took it away and this also solves the issue of testing whether
#1 is empty or not.

Thanks for the useful remarks. I am still learning.

Best,
-Hendri.


Donald Arseneau

unread,
Dec 12, 2003, 7:49:22 PM12/12/03
to
"Hendri Adriaens" <spotje38R...@hotmail.com> writes:

> > * What happens, if #1 is empty?
>
> Indeed, that was my question. What happens when #1 is empty.

\string applies to } and all hell breaks loose, with missing brace
errors. \string would only work on the first character (or other
token) of #1, so it isn't of general use anyway. Don't use it.

> Actually, the \string was proposed by the keyval package docs
> and I needed it in a previous situation. The current setup with
> \protected@xdef (thanks again!) does not need that indeed.

\protected@edef (or xdef) is indeed better than \string.

Donald Arseneau as...@triumf.ca

Rowland McDonnell

unread,
Dec 15, 2003, 3:14:00 PM12/15/03
to
Stefan Ulrich <ulr...@cis.uni-muenchen.de> wrote:

> Hendri Adriaens <spotje38R...@hotmail.com> writes:
[snip]

> > \edef\@test2{\@probber}%
> > \show\@test2}
>
> In LaTeX, always use \protected@edef, unless you know what
> you're doing.

Is there any documentation on this sort of thing outside source2e.tex?

Rowland.
(happy to buy a book)

[snip]

--
Remove the animal for email address: rowland....@dog.physics.org
PGP pub key 0x62DCCA78 Sorry - the spam got to me
http://www.mag-uk.org
UK biker? Join MAG and help keep bureaucracy at bay

0 new messages