1

I make concert programs for my student recitals using the ConcProg class. There is a lot of repetition in what songs are played, so I'd like to create a shorthand.

So instead of this

\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
    \end{composition}

Something like this.

\newcommand{\twinkle}{{Folk Song}{}{Twinkle Twinkle Little Star}}
\newcommand{\studentname}{{Student Name}}

\begin{composition}\twinkle\studentname
    \end{composition}

However, \newcommand seems to only like multiple sets of brackets when they're used for arguments for that specific new command. As far as I can tell, it ignores stand-alone brackets {i.e. brackets unrelated to arguments for that specific \newcommand or commands placed within the \newcommand}. In the instance of this custom environment, it throws an error.

Another example (that doesn't use a custom environment) follows.

%standard input 
\newcommand{\wbalTwo}[2] {
  This is the Wikibook about LaTeX
  supported by #1 and #2}
\item \wbalTwo{John Doe}{Anthea Smith}
%trying to use new command to input args. In this instance, it seems to ignore the internal braces and treats both internally-braced items as a single text string. 
\newcommand{\wbalTwo}[2] {
  This is the Wikibook about LaTeX
  supported by #1 and #2}
\newcommand{\passargs}

So is there an easy way to get these to have the same output?

6
  • Did you check this en.wikibooks.org/wiki/LaTeX/Macros ?
    – tachyon
    Dec 7, 2019 at 20:31
  • yes. did I miss something there?
    – Kale
    Dec 7, 2019 at 20:55
  • What's the definition of the composition environment?
    – egreg
    Dec 7, 2019 at 22:15
  • The composition environment is irrelevant. I've added a second example, along with a bit more info that I discovered while making it; hopefully it helps to clarify the issue.
    – Kale
    Dec 8, 2019 at 2:22
  • @Kale The definition of the composition environment is not irrelevant in the sense that information is needed on what arguments it processes and on how it processes them. Dec 8, 2019 at 15:59

1 Answer 1

0

From what you told us so far, one cannot reproduce the problem and therefore tracking down/tracing the source of the problem is, to some degree, associated with guesswork.

First some general remarks—I hope that my guesses are right and that my remarks are useful:

  1. At the time of gathering arguments for macros or environments from the token-stream, expansion is not triggered.
  2. In case it is present, (La)TeX will remove the outermost level of curly braces that surrounds an entire argument when inserting that argument into the replacement-text during expansion.

After "digging out" the ConcProg-class on CTAN (https://ctan.org/pkg/concprog), I found that the environment composition processes four arguments:

  1. ⟨author⟩
  2. ⟨years of birth (and death)⟩
  3. ⟨title of the composition⟩
  4. ⟨optional description⟩

Thus with

\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
⟨whatsoever environment-body⟩
\end{composition}
  • the first argument of the composition-environment will be: Folk Song,
  • the second argument of the composition-environment will be empty,
  • the third argument of the composition-environment will be: Twinkle Twinkle Little Star,
  • the fourth argument of the composition-environment will be: Student Name,

while with

\begin{composition}\twinkle\studentname
\end{composition}
  • the first argument of the composition-environment will be: \twinkle,
  • the second argument of the composition-environment will be \studentname,
  • the third argument of the composition-environment will be: \end,
  • the fourth argument of the composition-environment will be: composition.

This is because expansion is not triggered when LaTeX gathers arguments for macros or environments.

Depending on how the arguments get inserted when LaTeX carries out/expands the macros that underlie the composition-environment, this way of fetching arguments may lead to all kinds of weird/erroneous/problematic behaviour.

I can offer a customized variant of the composition-environment, called mycomposition, which takes care of expansion:

Actually the environment does not process any arguments at all. Instead it checks whether the next token in its environment-body is expandable or not. If it is, expansion will take place until finding a non-expandable token. (Be aware that curly opening braces { are not expandable tokens. ;-)) Then it will grab an argument. It does this four times for grabbing 4 arguments. Then internally it passes these four arguments to the macro underlying the composition-environment:

\documentclass{ConcProg}

\makeatletter
\newcommand\UD@CheckWhetherNextExpandable[2]{%
  \def\UD@reserved@a{#1}%
  \def\UD@reserved@b{#2}%
  \UD@@CheckWhetherNextExpandable
}%
\newcommand\UD@@CheckWhetherNextExpandable{%
  \futurelet\UD@reserved@c\UD@@@CheckWhetherNextExpandable
}%
\newcommand\UD@@@CheckWhetherNextExpandable{%
  \ifx\UD@reserved@c\@sptoken\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {\afterassignment\UD@@CheckWhetherNextExpandable\let\UD@reserved@c= }%
  {%
    \expandafter\ifx\noexpand\UD@reserved@c\UD@reserved@c
      \expandafter\UD@reserved@b
    \else
      \expandafter\UD@reserved@a
    \fi
  }%
}%
\newcommand\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d[1]{%
   \ifx\relax#1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
   {\expandafter\endgroup\UD@reserved@d}%
   {\UD@CheckWhetherNextExpandable
      {\expandafter\UD@@CheckWhetherNextExpandable}%
      {\expandafter\UD@AddNextTo\expandafter{\@gobble#1}\UD@reserved@d}%
   }%
}%
\newcommand\UD@AddNextTo[3]{%
  % \edef..\the\toks@-route prevents halving of hashes.
  \toks@\expandafter{#2{#3}}%
  \edef#2{\the\toks@}%
  \UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d{#1}%
}%
\newcommand\UD@ExpandAndAccumulateKArgsAndPassTo[2]{%
  \begingroup
  \def\UD@reserved@d{#2}%
  \expandafter\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d
  \expandafter{\romannumeral\number\number#1 000}%
}%
\newenvironment{mycomposition}%
               {\UD@ExpandAndAccumulateKArgsAndPassTo{4}{\composition}}%
               {\endcomposition}%
\makeatother


\newcommand{\twinkle}{{Folk Song}{}{Twinkle Twinkle Little Star}}
\newcommand{\studentname}{{Student Name}}


\begin{document}

\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}%
environment body
\end{composition}

\begin{mycomposition} \twinkle\studentname
environment body
\end{mycomposition}

\begin{mycomposition} \twinkle {Student Name}
environment body
\end{mycomposition}

\begin{mycomposition} {Folk Song}{}{Twinkle Twinkle Little Star} \studentname
environment body
\end{mycomposition}

\begin{mycomposition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
environment body
\end{mycomposition}

\end{document}

enter image description here

1
  • 1
    Thanks for this. What I ended up doing was just opening the composition environment within one of the newcommads (the student's name), with said newcommand taking an argument. The argument needs to be something that closes the composition environment (I used newcommands that were the songs).
    – Kale
    Dec 22, 2019 at 22:36

You must log in to answer this question.

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