I use a def as an alias like so:

\def\alias{\foo}

later on I would like to check if \alias is an alias for foo. (X is an alias of Y means the current definition of X is def\X{\Y}).

See the MWE below for what I tried:

MWE:

\documentclass{article}
%\usepackage{trace}
\def\foo{bar}
\def\bar{bar}

\newcommand{\isFoo}[1]{
%   \expandafter\if\expandafter\noexpand\alias\noexpand\foo  %false positives
%   \expandafter\ifx\alias\foo                               %this one compares text
%   \expandafter\ifx\expandafter\noexpand\alias\noexpand\foo %false negatives
        It is a \textbackslash foo #1
    \else
        Not a \textbackslash foo #1
    \fi
}
\begin{document}
    \def\alias{\foo}
    \isFoo{ab}

    \def\alias{\bar}
    \isFoo{xy}

    \def\bar{baz}
    \isFoo{xy}
\end{document}

The idea behind the expandafter/noexpand code is to expand \alias exactly once and then compare the two tokens without any further expansion to avoid comparing their return values.

  • I don't think I understand... You want to check if \alias expands to \foo without comparing if the contents of \foo using, for example, \expandafter\ifx\alias\foo? – Phelype Oleinik Aug 10 at 19:35
  • 1
    @PhelypeOleinik this is not fail proofed: \def\foo{\bar}\def\bar{A}\def\baz{A}\expandafter\ifx\foo\baz true\else false\fi yields true, though it should yield false. – Skillmon Aug 10 at 20:17
  • @Skillmon Makes sense... If OP had replied I would've done something similar to your approach, but using \string and \ifx instead of \detokenize and \pdf@strcmp, but then I forgot :P – Phelype Oleinik Aug 10 at 20:28
  • @PhelypeOleinik: Op disappeared from the keyboard for a while,... but in my simple case what you described did not work (see Skillmon's comment) which lead me to try getting noexpand in the mix. – ted Aug 10 at 21:00
  • @ted No problem :) Good that OP's problem is solved ;) – Phelype Oleinik Aug 10 at 21:12
up vote 3 down vote accepted

You could also just set up another alias for \foo and compare \alias to that with \ifx.

\documentclass{article}

% \def\foo{bar}
% \def\bar{bar}

\def\knownaliasforfoo{\foo}
\newcommand{\isFoo}[1]{%
  \ifx\alias\knownaliasforfoo
    It is a \textbackslash foo #1%
  \else
    Not a \textbackslash foo #1%
  \fi
}

\begin{document}
    \def\alias{\foo}
    \isFoo{ab}

    \def\alias{\bar}
    \isFoo{xy}

    \def\bar{baz}
    \isFoo{xy}
\end{document}

enter image description here

You can uncomment either or both of the commented lines and the output would remain the same.

With expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\ifisaliasTF}{mmmm}
 {% #1 = token to test
  % #2 = macro
  % #3 = true case
  % #4 = false case
  \ted_ifisalias:nnTF { #1 } { #2 } { #3 } { #4 }
 }

\prg_generate_conditional_variant:Nnn \tl_if_empty:n { f } { T,F,TF,p }
\prg_generate_conditional_variant:Nnn \tl_if_single:n { o } { T,F,TF,p }

\prg_new_conditional:Nnn \ted_ifisalias:nn { T,F,TF,p }
 {
  \token_if_macro:NTF #1
   {% the first argument is a macro
    \tl_if_empty:fTF { \token_get_arg_spec:N #1 }
     {% the macro has no arguments
      \tl_if_single:oTF { #1 }
       {% the expansion is a single token
        \exp_last_unbraced:No \token_if_eq_meaning:NNTF #1 #2
         {% the first level expansion of #1 is the same as #2
          \prg_return_true:
         }
         {% false
          \prg_return_false:
         }
       }
       {% false
        \prg_return_false:
       }
     }
     {% false
      \prg_return_false:
     }
   }
   {% false
    \prg_return_false:
   }
 }
\ExplSyntaxOff

\newcommand{\foo}{Whatever}
\newcommand{\alias}{\foo}
\newcommand{\notaliasA}[1]{\foo}
\newcommand{\notaliasB}{\foo\foo}

\begin{document}

\ifisaliasTF{\alias}{\foo}{Alias}{Not alias}

\ifisaliasTF{\foo}{\foo}{Alias}{Not alias}

\ifisaliasTF{\notaliasA}{\foo}{Alias}{Not alias}

\ifisaliasTF{\notaliasB}{\foo}{Alias}{Not alias}

\end{document}

enter image description here

The following should do what you want.

\documentclass[]{article}

\usepackage{pdftexcmds}

\def\alias{\foo}
\makeatletter
\newcommand\checkalias[2]
  {%
    \expandafter\expandafter\expandafter
    \checkalias@a\expandafter\expandafter\expandafter
      {\expandafter\detokenize\expandafter{#1}}{#2}%
  }
\newcommand\checkalias@a[2]
  {%
    \expandafter\ifnum
    \expandafter\pdf@strcmp\expandafter{\detokenize{#2}}{#1}=0
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
    \fi
  }
\makeatother

\begin{document}
\checkalias{\alias}{\foo}
  {still an alias}{no longer an alias}
\def\alias{\bar}
\checkalias{\alias}{\foo}
  {still an alias}{no longer an alias}
\end{document}

It doesn't check whether the first argument would grab any arguments though and is therefore not as safe as @egreg's check. I don't think it is worth it implementing the necessary checks without expl3 though.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.