6

I seem to be getting a spurious space from \@ifmtarg. The MWE below yields the image on the left where there is an spurious space before the end of the hyperref (for the last two cases). However, if I add an \unskip hack I obtain the desired result on the right hand side.

enter image description here enter image description here

Notes:

  • A simple use case of \@ifmtarg did not reproduce this problem for me so perhaps it has something to do with the way I am using it.
  • The MWE below is going to raise some WTF questions as to why I am using \renewcommand but this is a greatly simplified version from my actual use case, and probably can do with a lot of code clean up. But for now, this is the structure I have.

References:

Code:

\documentclass{article}
\usepackage{ifmtarg}
\usepackage{xcolor}
\usepackage{hyperref}

\makeatletter
    \newcommand{\IfIsEmptyArg}[3]{\@ifmtarg{#1}{#2}{#3}}
\makeatother


\newcommand{\SetTitle}[1]{}


\newcommand{\ExtractAndSetTitle}[2]{% 
    % #1 = macro csname in which the result is stored
    % #2 = text of title witout symbol
    \renewcommand{\SetTitle}[1]{%
        %\latexglobal\expandafter\renewcommand\csname #1\endcsname{%
        % Simplify above for this MWE.
        \expandafter\gdef\csname #1\endcsname{%
            ##1%
            \IfIsEmptyArg{\Symbol}{}{~\Symbol}% 
            %\unskip% Hack!!!!
        }%
    }%
    \SetTitle{#2}%
}% 


\begin{document}
\def\Symbol{$\times$}%  This works
\ExtractAndSetTitle{ExtractedTitle}{Times}%
\href{some.pdf}{\ExtractedTitle}%

\def\Symbol{\empty}%          This requires \unskip HACK
\ExtractAndSetTitle{ExtractedTitle}{Times}%
\href{some.pdf}{\ExtractedTitle}%

\def\Symbol{}%          This requires \unskip HACK
\ExtractAndSetTitle{ExtractedTitle}{Times}%
\href{some.pdf}{\ExtractedTitle}%
\end{document}
  • This looks like an expansion issue. I don't know \@ifmtarg, but either you are using it wrong or it has a bug. In your MWE, \IfIsEmptyArg is evaluating to false, and the space is due to the ~ (while \empty and {} are invisible of course). Just replace ~ by ! and it will become obvious :) – Xavier Jul 28 '13 at 1:04
5

You are using \@ifmtarg incorrectly. Here's a short example that shows your incorrect use:

enter image description here

\documentclass{article}
\usepackage{ifmtarg}% http://ctan.org/pkg/ifmtarg
\begin{document}
\makeatletter
Test 1: \@ifmtarg{}{YES}{NO} \par
Test 2: \@ifmtarg{ }{YES}{NO} \par
Test 3: \@ifmtarg{\empty}{YES}{NO} \par
Test 4: \@ifmtarg{\relax}{YES}{NO} \par
Test 5: \@ifmtarg{\@empty}{YES}{NO}
\end{document}

From the above \empty, \relax and \@empty are all considered not empty. Of course, you could use another method, like setting it in a box and testing whether it's width is non-zero:

enter image description here

\documentclass{article}
\makeatletter
\newcommand{\@ifmtarg}[1]
  {\setbox1=\hbox{\ignorespaces#1}\ifdim\wd1>\z@\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi}
\makeatother
\begin{document}
\makeatletter
Test 1: \@ifmtarg{}{YES}{NO} \par
Test 2: \@ifmtarg{ }{YES}{NO} \par
Test 3: \@ifmtarg{\empty}{YES}{NO} \par
Test 4: \@ifmtarg{\relax}{YES}{NO} \par
Test 5: \@ifmtarg{\@empty}{YES}{NO}
\end{document}

I guess it depends on your use case. If you don't have anything special but just want to test whether the contents of what is supplied is empty, then the above should work.

  • Both \def\Symbol{\empty} and \def\Symbol{} yield identical results, where \Symbol is what is being checked. Seems like an expansion issue then. – Peter Grill Jul 28 '13 at 4:43
  • After further testing this works. So back to the same solution as my earlier question on proper way to detect empty/blank text. Was trying to use \@ifmtarg as I thought it was more lightweight and did not have to deal with any side effects of executing the code twice. Oh well... Still very much appreciated though. – Peter Grill Jul 28 '13 at 4:51
3

\@ifmtarg considers empty only an argument consisting of zero or more spaces. In your case the argument is always \Symbol, which is definitely non empty.

Let's see what \@ifmtarg{\Symbol}{E}{N} does. Here's the definition of \@ifmtarg:

\begingroup
\catcode`\Q=3
\long\gdef\@ifmtarg#1{\@xifmtarg#1QQ\@secondoftwo\@firstoftwo\@nil}
\long\gdef\@xifmtarg#1#2Q#3#4#5\@nil{#4}
\endgroup

The first expansion does

\@xifmtarg\SymbolQQ\@secondoftwo\@firstoftwo\@nil{E}{N}

Thus the arguments for \@xifmtarg are:

  • #1 is \Symbol (#1 is not delimited)
  • #2 is empty (#2 is everything up to the first Q3
  • #3 is Q3
  • #4 is \@secondoftwo
  • #5 is \@firstoftwo (everything up to \@nil).

Therefore the next expansion is

\@secondoftwo{E}{N}

which returns N. If the argument to \@ifmtarg had been any sequence of spaces, they would be gobbled because TeX ignores space tokens when looking for an undelimited argument. So with \@ifmtarg{}{E}{N} we'd get

  • #1 is Q3 (the first non space token)
  • #2 is empty (#2 is everything up to the first following Q3
  • #3 is \@secondoftwo
  • #4 is \@firstoftwo
  • #5 is empty (everything up to \@nil).

so that the next step would be \@firstoftwo{E}{N} and then E.

You probably want

\makeatletter
\newcommand{\IfIsEmptyArg}[3]{%
  \expandafter\@ifmtarg\expandafter{#1}{#2}{#3}
}
\makeatother

so you look at the expansion of \Symbol rather than to \Symbol. Of course, with \def\Symbol{\empty}, the “non empty” branch would be followed.

3

The issue is that \@ifmtarg is evaluating \Symbol as not empty, probably because it is not expanding it. Whether it should or not, I have no idea.

The following code shows what's happening:

\documentclass{article}
\usepackage{ifmtarg}

\begin{document}

\def\Symbol{}
\makeatletter
\@ifmtarg{\Symbol}{\tt\string\Symbol{} is empty}{\tt\string\Symbol{} is not empty}%  
\makeatother

\end{document}

as it yields:

\Symbol is not empty

From there, your code outputs ~\Symbol, causing an empty space due to the ~.

If one expansion of \Symbol is enough (i.e., \Symbol expands directly to its content, not to other macros/commands which themselves might expand to an empty string), then the following test with \expandafter works:

\expandafter\@ifmtarg\expandafter{\Symbol}{...}{...}% 

One possible way to deal with more expansions would be to fully expand \Symbol (with an \edef) into a temporary variable, say \SymbolExpanded, and then run the above test on \SymbolExpanded.

  • This clarifies where the space is coming from. Now, just need to figure out how to get \Symbol expanded. – Peter Grill Jul 28 '13 at 4:43
  • @PeterGrill If one expansion is enough, the following does the trick in my example code: \expandafter\@ifmtarg\expandafter{\Symbol}{...}{...}. Another option would be to put the ~ inside \Symbol, i.e. add it to the definition of \Symbol whenever you define it to something "not empty". – Xavier Jul 28 '13 at 5:20
  • Yep, that expansion magic works for the \def\Symbol{} case, which is more important. Please update the answer with that. – Peter Grill Jul 28 '13 at 5:27
  • @PeterGrill Done :) – Xavier Jul 28 '13 at 18:50

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.