1

I read about the delimited macros in this answer. Actually, I would like to do something similar to the following:

\documentclass[a4paper]{article}

\def\insert this[#1]{%
  this macro: #1\\
}

\def\insert that[#1]{%
  that macro: #1\\
}

\begin{document}
  \insert this[test]
  \insert that[other]
\end{document}

I would expect that the above MWE would first evaluate to this macro: test and on the second line, it should evaluate to that macro: other. However, of course, the second definition overwrites the first definition, so it won't work. Is it possible, though, to use a construct as shown above? My key idea is that I would like to avoid typing different cumbersome macros, and instead, always use e.g. \insert to perform a special task. (I would like to avoid \insertthismacro and \insertthatmacro because it is more difficult to read and also more difficult to remember.)

Bonus: I also would like to expand this to an environment, as in the pseudocode below:

\begin{fancyenvironment} this[test] that[test] \end{fancyenvironment}

such that I don't even need to call a macro, but \insert is assumed on every line. I did some experiments with \@tfor, which I saw in the linked answer as well, but \@tfor loops over the individual characters, not over the lines.

  • 2
    I know this is just an example, but you probably should not redefine \insert - at least if you like footnotes. – moewe Jan 8 at 11:06
3

If you do

\def\foo this[#1]{...}

you are requiring that \foo is followed by this[; then comes argument #1, which goes on until finding ] at (relative) brace level zero.

If you later do

\def\foo that[#1]{...}

you are redefining \foo and requiring that it is followed by that. Then a call

\foo this[xyz]

will raise an error, because \foo is not followed by the correct tokens according to the current definition.

You can do

\def\foo #1[#2]{#1 macro: #2}

maybe using #1 for checking whether it is this or that to do further processing.

Be afraid of \def, though. Before using it, better adding

\newcommand{\foo}{}

so that LaTeX will tell you whether \foo already has a definition. You might then decide to redefine the command, but only if you know precisely what you're doing.

With your code you are redefining \insert and that's a very bad idea, because figure, table, \marginpar and \footnote will stop working and raise very weird errors.

3

TeX macros can't really be 'overloaded' like that. With

\def\myinsert this[#1]{%
  this macro: #1\\
}

\def\myinsert that[#1]{%
  that macro: #1\\
}

you define a macro called \myinsert in both cases. The only difference between the two definitions is how they grab their arguments. Since there can only be one macro with the name \myinsert, the second definition will overwrite the first and LaTeX will expect \myinsert to be followed by that[...] from now on. See also egreg's explanations in his answer.

Initially I wanted to write that one can't overload macros in TeX at all, but if you squint a bit, what LaTeX does for optional arguments is a kind of overloading. And so overloading is kind of possible, you just have to do the legwork yourself in TeX (and can use \newcommand in LaTeX for athe limited subset of overloadings with optional arguments).


You can just grab the 'this' or 'that' as a first argument and define your macro to act accordingly. A simple solution is implemented with helper macros. Where \myinsert <action>[<arg>] calls a helper macro called \myinsert@<action>. The idea could be extended by testing if the called macro is actually defined.

\documentclass[a4paper]{article}

\makeatletter
\newcommand{\myinsert@this}[1]{%
  this macro: #1\\
}
\newcommand{\myinsert@that}[1]{%
  that macro: #1\\
}
\newcommand{\myinsert@ooh}[1]{%
  ooh: #1\\
}
\makeatother

\newcommand*{\myinsert}{}% <- check that the name is not taken already
\def\myinsert #1[#2]{%
  \csname myinsert@#1\endcsname{#2}%
}

\begin{document}
  \myinsert this[test]
  \myinsert that[other]
  \myinsert ooh[other]
\end{document}

But I'm not convinced this is a good idea. I certainly feel this is fragile. LaTeX macros usually use a different syntax for a reason.


If you don't like

\myinsertthismacro{...}

why don't you try with

\myinsert{this}{...}

or a key-value interface

\myinsert[action=that]{...}

I don't think these two suggestions are far behind the desired

\myinsert this[...]

in terms of readability and they have the advantage that they are usual LaTeX syntax and thus more familiar.


I used \myinsert instead of \insert in this answer, because \insert is a primitive that should not be redefined (at least if you don't want to break \footnotes and other stuff).

0

In the discussion How does TeX look for delimited arguments? I tried to elaborate on how the processing of delimited and undelimited arguments is done by (La)TeX.


Using delimited arguments you can easily have your \insert-macro—better call it, e.g., \INSERT—as first argument catch an argument which is delimited by an opening-bracket and then a second argument which is delimited by a closing bracket and then feed the first argument to another macro which also uses delimited arguments, for forking depending on whether that first argument
is empty,
is the phrase "this",
is the phrase "that",
is something else.

Defining an environment fancyenvironment can be done, e.g., by means of the framework of the verbatim package.

The verbatim package does provide means for defining environments that do process input line by line and search for the sequence that ends the environment in question.

You can use its framework for within a token-register accumulating input line by line tokenized under verbatim-catcode-régime with an \INSERT-command added at the beginning of each line.

At the end of the environment you can have the content of the token register "flushed" towards \scantokens under normal catcode-régime.
In case you don't have eTeX-extensions available, you can have written the content of the token-register unexpanded to a scratch file and via \input have LaTeX process that scratch file under normal catcode régime.

\documentclass[a4paper]{article}
\usepackage{verbatim}
\makeatletter
%%----------------------------------------------------------------------
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<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>}%
%%
%% Without eTeX-extensions:
%%   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\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%% With eTeX-extensions:
%\newcommand\UD@CheckWhetherNull[1]{%
%  \romannumeral0\if\relax\detokenize{#1}\relax
%  \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
%  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
%  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
%}%
%%----------------------------------------------------------------------
%% Check whether argument contains no exclamation mark which is not nested 
%% in braces:
%%......................................................................
%% \UD@CheckWhetherNoExclam{<Argument which is to be checked>}%
%%                         {<Tokens to be delivered in case that argument
%%                           contains no exclamation mark>}%
%%                         {<Tokens to be delivered in case that argument
%%                           contains exclamation mark>}%
%%
\newcommand\UD@GobbleToExclam{}\long\def\UD@GobbleToExclam#1!{}%
\newcommand\UD@CheckWhetherNoExclam[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToExclam#1!}%
}%
%%----------------------------------------------------------------------
%%  \ThisThatFork grabs the first thing behind a
%%  a token-sequence of pattern  !!this!that!
%%......................................................................
\newcommand\ThisThatFork{}
\long\def\ThisThatFork#1!!this!that!#2#3!!!!{#2}%
%%----------------------------------------------------------------------
%% Your \insert-macro - better call it \INSERT because \insert is already
%% defined in LaTeX and I strongly recommend not to override that!
%%......................................................................
\newcommand\INSERT{}%
\long\def\INSERT#1[#2]{%
  \romannumeral0%
  \UD@CheckWhetherNoExclam{#1}{%
    \ThisThatFork!#1!this!that!{ empty macro: #2\\}%<-case #1 is empty/has not okens
                 !!#1!that!{ this macro: #2\\}%<-case #1 = this
                 !!this!#1!{ that macro: #2\\}%<-case #1 = that
                 !!this!that!{ something else macro: #2\\}%<-case #1 = something else without exclamation-mark.
                 !!!!%
  }{ something else macro: #2\\}%<-case #1 = something else with exclamation-mark.
}%
%%----------------------------------------------------------------------
%% Your environment fancyenvironment.
%% fancyenvironments cannot be nested within each other.
%% \end{fancyenvironment} should not be indented.
%%......................................................................    
\newtoks\UD@scratchtoks
\newwrite\UD@scratchwrite
\newenvironment{fancyenvironment}{}{}%
\def\fancyenvironment{%
  \begingroup
  \UD@scratchtoks={}%
  \let\do\@makeother
  \dospecials
  \catcode`\^^M\active
  \def\verbatim@startline{\verbatim@line{}}%
  \def\verbatim@addtoline##1{\verbatim@line\expandafter{\the\verbatim@line##1}}%
  \def\verbatim@processline{%
    \expandafter\UD@CheckWhetherNull\expandafter{\the\verbatim@line}{}%
    {\UD@scratchtoks\expandafter{\the\expandafter\UD@scratchtoks\expandafter\INSERT\the\verbatim@line^^J}}%%
    \def\verbatim@processline{%
      \UD@scratchtoks\expandafter{\the\expandafter\UD@scratchtoks\expandafter\INSERT\the\verbatim@line^^J}%
    }%
  }%
  \def\verbatim@finish{\expandafter\UD@CheckWhetherNull\expandafter{\the\verbatim@line}{}{\verbatim@processline}}%
  \verbatim@
}%
\def\endfancyenvironment{%
  % With eTeX-extensions:
  %   \expandafter\endgroup\expandafter\scantokens\expandafter{\the\expandafter\UD@scratchtoks\@percentchar}%
  % Without eTeX-extensions::
     \expandafter\endgroup
     \expandafter\begingroup
     \expandafter\UD@scratchtoks\expandafter{\the\expandafter\UD@scratchtoks\@percentchar}%
     \immediate\openout\UD@scratchwrite \jobname.scratchwrite %
     \immediate\write\UD@scratchwrite{\the\UD@scratchtoks}%
     \immediate\closeout\UD@scratchwrite
     \endgroup
     \input\jobname.scratchwrite %
}%


\makeatother

\begin{document}
\noindent\verb|\INSERT [test with nothing]|:\\
\INSERT [test with nothing]
\bigskip

\noindent\verb|\INSERT this[test with this]|:\\
\INSERT this[test with this]
\bigskip

\noindent\verb|\INSERT that[test with that]|:\\
\INSERT that[test with that]
\bigskip

\noindent\verb|\INSERT something else[test with something else without !]|:\\
\INSERT something else[test with something else without !]
\bigskip

\noindent\verb|\INSERT !something else![test with something else with !]|:\\
\INSERT !something else![test with something else with !]
\bigskip

\begin{verbatim}
\noindent\begin{fancyenvironment}
this[test]
that[test]
\end{fancyenvironment}
\end{verbatim}

\noindent\begin{fancyenvironment}
this[test]
that[test]
\end{fancyenvironment}

\end{document}

enter image description here

Don't be frightened by the \romannumeral0...-thingie:

This is just a trick for keeping expansion going until having the desired result:

\romannumeral does convert numbers into lowercase-roman notation.

With 0 following the \romannumeral, it is ensured that (La)TeX already found a digit and now keeps on searching for more digits.
While seeking more digits for \romannumeral, (La)TeX will keep expanding expandable tokens.
While seeking more digits for \romannumeral and hereby expanding expandable tokens, (La)TeX will take a space token for the end of the digit-sequence and will silently remove that space token and stop searching for digits.
When (La)TeX has this way gathered all digits of the number, it will convert the number to lowercase roman notation. But it will do that only in case the number found is positive. Otherwise it will just swallow that number, not delivering any token.
Thus you can (ab)use \romannumeral for triggering a lot of expansion-work as long as you ensure that after the expansion-work a non-positive number, e.g. the number 0 is found.

In the discussion How can I know the number of expandafters when appending to a csname macro? I also tried to elaborate on expansion-triggering via \romannumeral.

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.