14

I saw this answer, which uses the etoolbox package to create a macro with an optional argument. Unfortunately, I can't get it to work. Here is a minimal working example:

\documentclass[12pt]{article}
\usepackage{etoolbox}

\newcommand\mymacrotwo[2][]{
  \ifstrempty{#2}{
    #1: none
  }{
    #1: #2
  }
}

\begin{document}
\mymacrotwo{hello}

\mymacrotwo{hello}{world}
\end{document}

This outputs:

: hello
: hello world

Not only are the colons in the wrong place, but it doesn't display the none if the second argument isn't defined. What's the problem?

I also tried this variant:

\documentclass[12pt]{article}
\usepackage{etoolbox}

\newcommand{\mymacro}[2]{#1 \ifboolexpr{ test {\ifdef{#2}} } {#2} {none}}

\begin{document}
\mymacro{hello}

\mymacro{hello}{world}
\end{document}

but this outputs:

hello
hello orldworld

which clearly isn't right either.

Michael A
  • 1,525
  • 2
  • 11
  • 16
  • Your definition requires the optional argument #1 to be supplied using []. As in \mymacrotwo[hello]{world}. – Werner Nov 19 '13 at 21:14
  • @Werner Ah the problem was because I used [2][] instead of just [2], I guess, right? – Michael A Nov 19 '13 at 21:15
  • Even with \newcommand{\mymacrotwo}[2]{...} you can't use \mymacrotwo{hello} and hope that #2 is considered empty. – egreg Nov 19 '13 at 21:16
  • @egreg Will that result in undefined behavior? If I use just [2], and don't make any other changes to my document, everything seems to work. – Michael A Nov 19 '13 at 21:18
  • @fortranuser: Perhaps provide examples of the types of input and expected output in your post. From there, community members might help you in your formal definition. – Werner Nov 19 '13 at 21:18
  • @Werner I'm just planning to use this with text input, and output just like in the example (maybe with formatting like \textbf, but probably not). Is there anything else I should provide? – Michael A Nov 19 '13 at 21:19

1 Answers1

16

If a TeX macro is defined as having two arguments, TeX will always assign some token to both arguments, or raise an error.

Defining

\newcommand\mymacrotwo[2]{
  \ifstrempty{#2}{
    #1: none
  }{
    #1: #2
  }
}

has already some weak points, because you're adding several spaces which will show up in the printout. Better would be

\newcommand\mymacrotwo[2]{%
  \ifstrempty{#2}%
   {%
    #1: none%
   }%
   {%
    #1: #2%
   }%
}

How to align the braces for the alternatives is a matter of personal taste, but end-of-lines should be masked off unless you do want a space to show up.

Let's see what happens if you type

\mymacrotwo{hello} and some text

The macro has two arguments; the first one is determined to be hello, because a brace is scanned; the second argument will be a: when looking for an argument, TeX takes the first non space token it finds, unless it is {; in this case the argument is whatever appears up to the matching }.

If you call

\mymacrotwo{hello}
and some text

it would be exactly the same, because TeX converts the end-of-line into a space and spaces are ignored when looking for an argument.

TeXnical note: here I'm talking about undelimited arguments, the kind that is looked for when macros defined with \newcommand are concerned.

Leaving a blank line wouldn't help either: with

\mymacrotwo{hello}

and some text

the second argument would be \par, because TeX converts an empty line into a \par token.

Let's verify it. I'll use a simplified version of the macro that just prints its arguments:

\documentclass{article}
\newcommand{\mymacrotwo}[2]{%
  ``{\ttfamily \#1 is \detokenize{#1}, \#2 is \detokenize{#2}}''%
}

\begin{document}
\mymacrotwo{hello} and some text

\mymacrotwo{hello}
and some text

\mymacrotwo{hello}

and some text
\end{document}

enter image description here

So if you want to use your macro as intended, you must call it either

\mymacrotwo{hello}{}

or

\mymacrotwo{hello}{world}

Actually, with xparse one could define a macro with the characteristics you'd like, but it's debatable whether this fits into LaTeX syntax.

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\mymacrotwo}{ m g }
 {%
  \IfNoValueTF{#2}%
   {%
    #1: none%
   }
   {
    #1: #2%
   }%
 }

\begin{document}

\mymacrotwo{hello} and some text

\mymacrotwo{hello}{world} and some text

\end{document}

enter image description here

I surely wouldn't recommend using this feature.

egreg
  • 1,121,712
  • I'd also add that the definition in the question (\newcommand\mymacrotwo[2][]{...}) means that the first argument is optional and defautls to the empty string. So it can/should be used like \mymacrotwo{hello} or \mymacrotwo[world]{hello}. – Oleg Domanov Nov 20 '13 at 07:26