0

Resolution: The problem was with the outdated version of moderncv I was using. I put some additional details at the end of the question, but I will delete this question. Thanks to those who wrote to clarify about how \ifx works. If I had understood this better, I would have realized the issue right away.


I have some code that uses a package. The package supplies some commands that have optional arguments. I am supplying some text to those arguments, but I want to be able to compile an alternate version of my document wherein that text is hidden.

So I'm trying to define a boolean flag of some sort such that when it is set to true, the result is as if those arguments are supplied as empty. Unfortunately, no approach that I've tried seems to accomplish this.

I will include a MWE below that illustrates a couple of the methods I tried out, and also shows why the results are not satisfactory. I am at a loss as to what else I could try, so any help would be much appreciated!

\documentclass{article}

\usepackage{etoolbox}

% I want a flag that, if true, will cause certain strings to be hidden, as if
% they were not in the document at all.  Below I try a couple ways of defining
% such a flag.
\newif\ifhidestuff
    \hidestufftrue
%   \hidestufffalse
    
\newtoggle{hidestuff}
    \toggletrue{hidestuff}
%   \togglefalse{hidestuff}
    
% Below is an example of a command that behaves differently according as one
% of its arguments is empty
\newcommand{\withoptarg}[2]{#1{%
    \ifx#2\else{ and #2}\fi}}

\newcommand\hidden[1]{\ifhidestuff%
    % not sure what to put here
    \else
        #1
    \fi}

\begin{document}

% The \hidden command seems to work fine on its own
The stuff between the quotes might be hidden: ``\hidden{stuff}''

% Now let's see if we can hide an optional argument to the \withoptarg command

This is the output I want when the flag is true: \withoptarg{this}{}

This is the output I want when the flag is false: \withoptarg{this}{that}


With my first approach, I instead get: \withoptarg{this}{\iftoggle{hidestuff}{}{that}}

With my second approach, I also get: \withoptarg{this}{\hidden{that}}

\end{document}

Here is the output that I get:

sample output


Update: The package in question was moderncv. I coded \withoptarg to mimic the way \cventry was implemented, to make the simplest possible MWE. However - mea culpa - I was using an outdated version of the package. The very next version includes a comment by the author that it "corrected several bugs linked to the code for checking for empty arguments in \cventry." Indeed, upgrading to the latest version of moderncv solved my issue.

If my understanding of how \ifx works had been better, I might have identified the bug and realized what was going on. In any case, though, I at least learned something about this here.

I am going to delete this question, but I'll leave it up for a little while just to acknowledge the assistance from those who wrote to help.

9
  • BTW, "optional argument" usually means \newcommand{\mymacro}[2][default]{definition} gets called by \mymacro[optional]{manditory}. You're specifically wanting to test if an argument is empty, but it's not optional.
    – Teepeemm
    Commented Dec 22, 2021 at 3:27
  • @Teepeemm: You're right, of course. This is how the package works. Here I defined \withoptarg to mirror the way the commands are defined in the package (though those have multiple "optional arguments" actually.) Anyway, do you think I should remove the optional-arguments tag? Commented Dec 22, 2021 at 3:49
  • Anyway, there are some options including • learn how ifx and expansion works in TeX properly (in this particular case the \hidden command is already expandable, so you want to fully expand the argument before passing to the command) • learn expl3 • learn Lua and write the command in LuaTeX. I'd recommend the last approach
    – user202729
    Commented Dec 22, 2021 at 3:49
  • Please provide us with more information. Which command from which package do you want to redefine conditionally?
    – Niranjan
    Commented Dec 22, 2021 at 5:44

1 Answer 1

1

You can define a macro to deliver either \@gobble or \@firstofone depending on an \if..-switch.
You can define a macro to deliver either \@firstoftwo or \@scondoftwo depending on an \if..-switch.

The \@firstoftwo/\@scondoftwo-variant can be used for toggling between \phantom{\mbox{text}} and \@firstofone{\mbox{text}} or the like if you wish horizontal/vertical space to be reserved in case of text not being visible.

\documentclass{article}
\newif\ifhidestuff

\newcommand\StuffToHide{%
  \csname @\ifhidestuff gobbl\else firstofon\fi e\endcsname
}%

\newcommand\StuffToShowOrHide{%
  \csname @\ifhidestuff second\else first\fi oftwo\endcsname
}%

\newcommand\withoptarg[2][Optional Default]{%
  This is the optional argument in parentheses: (#1)\\
  This is the mandatory argument in parentheses: (#2)
}%

\parindent=0pt \parskip=\medskipamount

\begin{document}

\verb|\hidestufffalse|:\hidestufffalse

\withoptarg{Mandatory}

\withoptarg[\StuffToHide{Optional User-Provided}]{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg}{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg[]}{Mandatory}

\withoptarg[\csname\StuffToShowOrHide{@firstofone}{phantom}\endcsname{\mbox{Optional User-Provided}}]{Mandatory}

\medskip\hrule

\verb|\hidestufftrue|:\hidestufftrue

\withoptarg{Mandatory}

\withoptarg[\StuffToHide{Optional User-Provided}]{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg}{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg[]}{Mandatory}

\withoptarg[\csname\StuffToShowOrHide{@firstofone}{phantom}\endcsname{\mbox{Optional User-Provided}}]{Mandatory}

\end{document}

enter image description here



If you wish to check for emptiness of an argument, i.e., the argument containing no token at all, I can offer two variants of the test.
One variant, \CheckWhetherNullVanilla is slow but doesn't require whatsoever TeX-extensions. It is based on using \string and applying brace-hacks while cranking out whether the closing } behind the empty argument was stringified or the first token, not being an opening {, of the non-empty argument was stringified or the first token, being an opening {, of the non-empty argument was stringified.
The other variant, \CheckWhetherNulleTeX is faster but requires eTeX-extensions as it is based on \detokenize, which in case of the ⟨general text⟩ provided via the macro-argument being empty delivers no token at all and otherwise delivers character-tokens whose category differs from the category of $ so that \ifcat can be used for doing the trick. (Instead of \ifcat$\detokenize{...}$...\else...\fi you could as well use \if\relax\detokenize{...}\relax...\else...\fi, but that relies on \relax not being redefined to deliver two subsequent equal tokens while I saw users doing all kinds of weird things within local scopes.)

Besides this, there also is a test for checking whether an argument is blank, i.e., is empty or contains explicit space-tokens only, \CheckWhetherBlank, which is based on \CheckWhetherNullVanilla or \CheckWhetherNulleTeX.

The tests look for the presence of tokens, but they don't expand expandable tokens, thus, e.g., \CheckWhetherNulleTeX{\empty}{empty}{not empty} yields not empty because, although just vanishing and not yielding any token when being expanded, \empty itself is a token and therefore \CheckWhetherNulleTeX's first argument is not empty but consists of the token \empty.

Remark:

In the subsequent coding-example you find \romannumeral.
This may seem confusing at first glimpse.

In the subsequent coding-example \romannumeral is not used for obtaining lowercase-roman-representation of whatsoever number but is (ab?)used for triggering a lot of expansion-work and flipping-macro-arguments-around-work so that in case of needing to be in control of expansion you don't need so many/long \expandafter-chains.

\romannumeral usually is used for "gobbling" tokens that form a TeX-⟨number⟩-quantity and in return for them delivering character-tokens which form the representation of the value of that TeX-⟨number⟩-quantity in lowercase roman numerals.
\romannumeral in any case triggers "gobbling" those tokens that form the TeX-⟨number⟩-quantity. But in case that TeX-⟨number⟩-quantity does have a value which is not positive, silently, i.e., without error-message or the like, no tokens at all are delivered in return.
Besides this while searching for tokens belonging to the TeX-⟨number⟩-quantity, expansion of expandable tokens is not suppressed.

Thus you can (ab?)use \romannumeral's searching for tokens belonging to the TeX-⟨number⟩-quantity for having (La)TeX doing a lot of expansion-work and flipping-macro-arguments-around-work as long as it is ensured that in the end a TeX-⟨number⟩-quantity is found whose value is not positive.

In the subsequent coding-example as "TeX-⟨number⟩-quantity whose value is not positive" the \chardef-token \UD@stopromannumeral is used.

This way the result of a macro is delivered after triggering two expansion-steps, e.g., after two "hits" with \expandafter:

The first one delivers the toplevel-expansion, whose first token is \romannumeral.

The second one triggers carrying out the \romannumeral-routine which in turn triggers all subsequent expansion-steps until the result is there.

In case you wish things to work out in tabular-environments/alignments etc as well, make sure that user-provided arguments, which might contain things like &, are nested in curly braces until the last expansion-step delivers the result. Otherwise the & of the user-provided-arguments might be taken for markers for the end of a table-cell at the wrong moment in time.

\documentclass[a4paper]{article}

\makeatletter
%%=============================================================================
%% PARAPHERNALIA:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@stopromannumeral,
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%% In the following code \romannumeral is not used for
%%-----------------------------------------------------------------------------
%% Check whether argument is empty, slow, but no eTeX-extensions or
%% the like required:
%%.............................................................................
%% \CheckWhetherNullVanilla{<Argument which is to be checked>}%
%%                         {<Tokens to be delivered in case that argument
%%                           which is to be checked is empty>}%
%%                         {<Tokens to be delivered in case that argument
%%                           which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\CheckWhetherNullVanilla[1]{%
  \romannumeral\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
  \expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty, based on \detokenize, thus eTeX-extensions
%% are required:
%%.............................................................................
%% \CheckWhetherNulleTeX{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked is empty>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked is not empty>}%
\newcommand\CheckWhetherNulleTeX[1]{%
  \romannumeral\ifcat$\detokenize{#1}$%
  \expandafter\expandafter\expandafter\UD@stopromannumeral
  \expandafter\UD@firstoftwo\else
  \expandafter\expandafter\expandafter\UD@stopromannumeral
  \expandafter\UD@secondoftwo\fi
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is blank (empty or only explicit space-tokens):
%%-----------------------------------------------------------------------------
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \CheckWhetherBlank{<Argument which is to be checked>}%
%%                   {<Tokens to be delivered in case that
%%                     argument which is to be checked is blank>}%
%%                   {<Tokens to be delivered in case that argument
%%                     which is to be checked is not blank>}%
%% Instead of \CheckWhetherNulllVanilla you can as well use
%% \CheckWhetherNullleTeX
\newcommand\CheckWhetherBlank[1]{%
  \romannumeral\expandafter\expandafter\expandafter\UD@secondoftwo
  \expandafter\CheckWhetherNullVanilla\expandafter{\UD@firstoftwo#1{}{}}%
}%
\makeatother

\parindent=0pt \parskip=\medskipamount

\begin{document}

\verb|\CheckWhetherNullVanilla{}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{}{empty}{not empty}

\verb|\CheckWhetherBlank{}{blank}{not blank}|:\\
\CheckWhetherBlank{}{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{ }{empty}{not empty}|:\\
\CheckWhetherNullVanilla{ }{empty}{not empty}

\verb|\CheckWhetherNulleTeX{ }{empty}{not empty}|:\\
\CheckWhetherNulleTeX{ }{empty}{not empty}

\verb|\CheckWhetherBlank{ }{blank}{not blank}|:\\
\CheckWhetherBlank{ }{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{{some}thing}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{{some}thing}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{{some}thing}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{{some}thing}{empty}{not empty}

\verb|\CheckWhetherBlank{{some}thing}{blank}{not blank}|:\\
\CheckWhetherBlank{{some}thing}{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{something}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{something}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{something}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{something}{empty}{not empty}

\verb|\CheckWhetherBlank{something}{blank}{not blank}|:\\
\CheckWhetherBlank{something}{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{\empty}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{\empty}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{\empty}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{\empty}{empty}{not empty}

\verb|\CheckWhetherBlank{\empty}{blank}{not blank}|:\\
\CheckWhetherBlank{\empty}{blank}{not blank}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .