0

I am trying to create a command with two or three arguments, that creates a new command.

In my classfile I have:

\def\foobar#1#2{\gdef\foo{#1, #2, \@ifnextchar\bgroup{foo}{bar}}}

If I call \foobar{X}{Y}, \foo generates X, Y, foo, but if I call \foobar{X}{Y}{Z} I get Missing \begin{document}. instead of X, Y, barZ.


Without using gdef it works:

\def\baz#1#2{#1, #2, \@ifnextchar\bgroup{foo}{bar}}
  • The Missing \begin{document} is because you're using it in the preamble, and it looks like a command to typeset stuff. Move the call after \begin{document}. Then try \def\foobar#1#2{\gdef\foo{#1, #2, \@ifnextchar\bgroup{foo}{bar}}\foo}\foobar{X}{Y}\par\foobar{X}{Y}{Z} (don't forget \makeatletter before) to see if it is what you want. – Phelype Oleinik May 22 '18 at 23:49
  • I see that @Manuel’s answer still has only got one upvote, which is mine. If you found that answer useful, consider upvoting it, as well as accepting it. – GuM May 23 '18 at 8:16
  • I already accepted it and upvoted it, but my reputation is not high enough for upvotes to be visible. – MatthiasF999 May 26 '18 at 9:59
2
\def\foobar#1#2{%
  \@ifnextchar\bgroup
    {\gdef\foo{#1, #2, foo}}
    {\gdef\foo{#1, #2, bar}}%
}

You need to put \@ifnextchar in the correct position. Which still doesn't do what you want. This is an option \foobar{x}{y} defines \foo to be x, y, bar; and \foobar{x}{y}{z} defines \foo to be x, y, z.

\def\foobar#1#2{%
  \@ifnextchar\bgroup
    {\foobaraux{#1}{#2}}
    {\foobaraux{#1}{#2}{bar}}%
}
\def\foobaraux#1#2#3{%
  \gdef\foo{#1, #2, #3}%
}

May be cleaner with xparse

\usepackage{xparse}
\NewDocumentCommand \foobar { m m g }
 {%
  \IfValueTF {#3}
   {\gdef\foo{#1,#2,#3}}
   {\gdef\foo{#1,#2,bar}}%
 }

altough the classic syntax is with an optional argument \foobar{x}{y}[optional].

| improve this answer | |
  • 2
    If I understand correctly what the OP says in their question, it should be \IfValueTF{#3}{\gdef\foo{#1,#2,bar#3}}{\gdef\foo{#1,#2,foo}}. – GuM May 23 '18 at 0:26
1

In the classfile you have:

\def\foobar#1#2{\gdef\foo{#1, #2, \@ifnextchar\bgroup{foo}{bar}}}

Why do you use \def instead of \newcommand?

Be that as it may. According to that definition \foobar will in any case process exactly two arguments in order to define the macro \foo. \foobar will just define but not call/use/carry out/expand the macro \foo.
Therefore usage of \foobar in any case will not lead to typesetting anything.

\foobar{X}{Y} globally defines the macro \foo to expand to:
X, Y, \@ifnextchar\bgroup{foo}{bar}.

If {Z} is appended behind that call to \foobar{X}{Y} (so that the input looks like
\foobar{X}{Y}{Z}), defining \foo takes place in the same way: \foobar still processes just two arguments, i.e., the arguments {X} and {Y}, for defining the \foo-macro while not attempting to typeset anything. Then processing the \foobar-macro is done. Then (La)TeX will in the input-stream find the token sequence {Z} which is not processed yet as it does not form one of \foobar's arguments, and (La)TeX will attempt to typeset that token sequence. This typesetting-attempt in turn leads to an error message when it takes place within the document's preamble, before \begin{document}.


By the way:

Always care about the time when things get carried out.
E.g., there is a 'definition-time', and there is an 'expansion-time'.

With your attempt, the \@ifnextchar-forking does not take place at the time of defining the \foo-macro. It will take place each time when the \foo-macro is expanded/carried out.

Perhaps having the \@ifnextchar-forking carried out at the time of defining \foo is closer to what you want:

\newcommand\foobar[2]{%
  \@ifnextchar\bgroup%
              {\foobarhelper{#1}{#2}{bar}}%
              {\foobarhelper{#1}{#2}{foo}{}}%
}%
\newcommand\foobarhelper[4]{\gdef\foo{#1, #2, #3#4}}

If in the preamble you have, e.g.,

\foobar{X}{Y}%
\begin{document}

, this yields:

\@ifnextchar\bgroup%
            {\foobarhelper{X}{Y}{bar}}%
            {\foobarhelper{X}{Y}{foo}{}}%
\begin{document}

The \@ifnextchar-check will find that the \begin-token's meaning does not equal the meaning of the token \bgroup, thus that check will deliver
\foobarhelper{X}{Y}{foo}{} while leaving the \begin-token and everything behind it in place:

\foobarhelper{X}{Y}{foo}{}%
\begin{document}

The sequence \foobarhelper{X}{Y}{foo}{} in turn yields -- \foobarhelper's fourth argument is empty --
\gdef\foo{X, Y, foo}:

\gdef\foo{X, Y, foo}
\begin{document}

If in the preamble you have, e.g.,

\foobar{X}{Y}{Z}%
\begin{document}

, this yields:

\@ifnextchar\bgroup%
            {\foobarhelper{X}{Y}{bar}}%
            {\foobarhelper{X}{Y}{foo}{}}%
{Z}%
\begin{document}

The \@ifnextchar-check will find that the meaning of the opening brace from the sequence {Z} does equal the meaning of the token \bgroup, thus that check will deliver
\foobarhelper{X}{Y}{bar} while leaving that opening brace and everything behind it in place:

\foobarhelper{X}{Y}{bar}%
{Z}%
\begin{document}

The sequence \foobarhelper{X}{Y}{bar}{Z} in turn yields
\gdef\foo{X, Y, barZ}:

\gdef\foo{X, Y, barZ}
\begin{document}
| improve this answer | |

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.