# Identifying if macro is an alias

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
• @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

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}


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}


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.