1

I'm trying to make a macro. It works for the most part, except it has some weird behavior. If I have the macro called within some text and then insert a \newline, it creates a newline before it outputs the macro text. I would like the macro text to be inserted before the newline.

So, when I use the code:

\documentclass[a4paper,12pt,noindent]{article}

\usepackage{parskip}

\makeatletter
\newcommand{\address}[1]{%
    \ifdefined\@address % Address is already defined
        \if\noexpand\@empty#1   % Argument is empty
            \@address\mbox{}
        \else % Argument is non-empty
            \def\@address{#1}
        \fi
    \else   % Address is not defined
        \if\noexpand\@empty#1   % Argument is empty
            \def\@address{}
        \else   % Argument is non-empty
            \def\@address{#1}
        \fi
    \fi
}
\makeatother

\address{John Smith\\
         12345 Luggage Way\\
         Portland, OR, 97231}

\begin{document}

    Before \address \newline
    After

\end{document}

I get:

Image of Latex Output: Before (newline) 12345 Luggage Way (newline) Portland, OR, 97231 After

I would be expecting a after the address is finished printing and not before.

Interestingly, when I remove all text on that line except for the macro and the \newline, the LaTeX complains that there is no line to end. Not sure why that is.

  • \if\noexpand\@empty#1 is surely a wrong test for emptyness of #1. – egreg Feb 25 '17 at 23:23
  • It may be, but it was working... I'm open to suggestions. – Spartacus Feb 25 '17 at 23:26
  • No, it won't generally work. I added some suggestions to my answer. – egreg Feb 25 '17 at 23:42
3

When you do

\address \newline

the token \newline is taken as the argument to \address. Since \@address has already been defined by calling \address in the preamble, the true branch in \ifdefined\@address is taken.

Now \if\noexpand\@empty\newline is tested. The \if conditional does complete expansion until finding nonexpandable tokens. So it expands \noexpand, which makes \@empty temporarily equivalent to \relax; then \newline is expanded; its standard definition is \protect\newline• (where stands for a space in the name). In that situation, \protect is equivalent to \relax (it is during normal typesetting), so we have

\if\relax\relax\newline•

The test returns true. So \newline• is executed: it contains the actual code for getting a new line; \@address\mbox{} follows.


If a macro is defined to have an argument, it will always look for one: either the text between braces if a { follows, or the next token.

You should use a \printaddress macro instead of overloading \address.

Note also that \if\noexpand\@empty#1 is not at all a test for emptiness of #1. Indeed, if by chance #1 is really empty (call such as \address{}), your code would compare \@empty (made equivalent to \relax) with a space token (which follows #1), so returning false. If #1 is not empty, the test will return true whenever the first token of #1, after full expansion, is not a character token.

A reliable test for emptiness is

\if\relax\detokenize{#1}\relax

As I said, I wouldn't overload \address, but if that's what you want, you need to redefine it not to have an argument. The first call will set the address, the subsequent ones will print it.

\documentclass{article}
\usepackage{parskip}

\makeatletter
\newcommand{\address}[1]{%
  % this is for the first call
  \def\@address{#1}%
  % subsequent calls will print the address
  \let\address\print@address
}
\newcommand{\@address}{}% initialize
\newcommand\print@address{\@address\mbox{}}
\makeatother

\address{John Smith\\
         12345 Luggage Way\\
         Portland, OR, 97231}

\begin{document}

Before \address \newline
After

\end{document}

enter image description here

  • Any explanation for a downvote? – egreg Feb 27 '17 at 17:10
1

egreg already explained why the tests etc. fails.

Here is some code golfing with xparse and the g type which establishes an optional argument delimited by {} (actually, this is weird!). I prefer a traditional o type argument:

\documentclass[a4paper,12pt]{article}

\usepackage{parskip}

\usepackage{xparse}

\makeatletter

\NewDocumentCommand{\addressweird}{+g}{%
  \@ifundefined{@addressweird}{%
    \IfValueTF{#1}{%
      \def\@addressweird{#1}%
    }{%
      \def\@addressweird{}%
    }%
  }{%
    \IfValueTF{#1}{%
      \def\@addressweird{#1}%
    }{%
      \@addressweird\mbox{}%
    }%
  }%
}

\NewDocumentCommand{\address}{+o}{%
  \@ifundefined{@address}{%
    \IfValueTF{#1}{%
      \def\@address{#1}%
    }{%
      \def\@address{}%
    }%
  }{%
    \IfValueTF{#1}{%
      \def\@address{#1}%
    }{%
      \@address\mbox{}%
    }%
  }%
}



\title{Hello}

\makeatother

\addressweird{John Smith\\
         12345 Luggage Way\\
         Portland, OR, 97231
       }


\address[Gandalf The Gray\\
         Moria\\
         Middle of Middle Earth
       ]


\begin{document}
    Before \address \newline
    After

    \address

    Before \addressweird \newline After
\end{document}

enter image description here

  • I wouldn't recommend using g arguments. – egreg Feb 25 '17 at 23:45
  • @egreg: That's why I wrote weird. I would not use it for personal purposes neither! Perhaps traditional o is better. – user31729 Feb 25 '17 at 23:46

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.