1

I want to write a macro \createTheorem that creates two environments: a normal one and a "capitalised" one.

For example, \createTheorem{defi}{Definition} will create :

  • an environment \begin{defi}...\end{defi}
  • and an environment \begin{Defi}...\end{Defi}.

How would you do that? I would like to know why my code doesn't work.

My code

Here is what I have tried. It doesn't work, the error being

Missing \endcsname inserted. \protect l.13 \documentclass{article}

\usepackage{amsmath}

\newtheorem{theoremForCounter}{theoremForCounter}

\newcommand{\createTheorem}[2]
{ 
 \def\nameNewTheoremCapitalized{\MakeUppercase{#1}}
 \newtheorem{#1}[theoremForCounter]{#2}
 \newtheorem{\nameNewTheoremCapitalized}[theoremForCounter]{#2}
}

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi}
This is a test.
\end{defi}

\begin{Defi}
This is a test.
\end{Defi}

\end{document}
4
  • 2
    MakeUppercase is not expandable (case 2 of my question). And even if it were, it's usually desirable to expand the arguments before passing it to commands (although it isn't necessary in this case).
    – user202729
    Jun 12, 2022 at 11:45
  • I've tried indeed to \expandafter but it didn't work. Thanks for your interest in my question.
    – Colas
    Jun 12, 2022 at 11:53
  • Should the two environments behave the same?
    – egreg
    Jun 13, 2022 at 6:43
  • @egreg No: \begin/\end{Defi} will have a thicker frame than \begin/\end{defi}.
    – Colas
    Jun 13, 2022 at 10:02

3 Answers 3

1

I'm not sure what would the usage of this would be: having two environments defi and Defi that do exactly the same is useless and possibly confusing.

Anyway, you can use \text_titlecase:n (with a LaTeX released after March 2020).

\documentclass{article}
\usepackage{amsthm} % probably you wanted this one

\newcounter{counterForTheorem}

\ExplSyntaxOn
\cs_new:Npn \uppercasefirst #1
 {
  \str_uppercase:f { \tl_head:n { #1 } }
  \tl_tail:n { #1 }
 }
\ExplSyntaxOff

\newcommand{\createTheorem}[2]{%
  \newtheorem{#1}[counterForTheorem]{#2}%
  \newtheorem{\uppercasefirst{#1}}[counterForTheorem]{#2}%
}

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi}
This is a test.
\end{defi}

\begin{Defi}
This is a test.
\end{Defi}

\end{document}

Alternative implementation:

\documentclass{article}
\usepackage{amsthm} % probably you wanted this one

\newcounter{counterForTheorem}

\makeatletter
\newcommand{\createTheorem}[2]{%
  \newtheorem{#1}[counterForTheorem]{#2}%
  \begingroup
  \edef\temp@a{\@car#1\@nil}%
  \edef\temp@b{\@cdr#1\@nil}%
  \begingroup\edef\x{\endgroup\uppercase{\def\noexpand\temp@a{\temp@a}}}\x
  \edef\temp@a{\temp@a\temp@b}%
  \expandafter\endgroup\expandafter\newtheorem\expandafter{\temp@a}[counterForTheorem]{#2}%
}
\makeatother

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi}
This is a test.
\end{defi}

\begin{Defi}
This is a test.
\end{Defi}

\end{document}
2
  • I think the point of the text functions is that you don't use it for "programmatic" things. But yes titlecase is more concise in this case.
    – user202729
    Jun 13, 2022 at 10:53
  • @user202729 Changed to use \str_uppercase:f
    – egreg
    Jun 13, 2022 at 16:48
1

As mentioned above, MakeUppercase is not expandable. You can use expl3 functions str_uppercase:f instead which is expandable:

%! TEX program = lualatex
\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn
\newcommand{\createTheorem}[2]
{ 
 \def\nameNewTheoremCapitalized{\str_uppercase:f{\tl_head:n{#1}}\tl_tail:n{#1}}
 \newtheorem{#1}{#2}
 \exp_args:Nx\newtheorem{\nameNewTheoremCapitalized}{#2}
}
\ExplSyntaxOff

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi}
This is a test.
\end{defi}

\begin{Defi}
This is a test.
\end{Defi}

\end{document}

Remark:

  • in pdflatex \tl_head will take the first byte of the name instead of the first character, so I don't know what happens if the first character is not a simple ASCII character.
  • If the first character is not a lowercase character newtheorem will raise error because the two names are identical.
  • Your macro definition has spurious spaces. Not so with \ExplSyntaxOn.
  • In this case the implementation of newtheorem happens to already expand the argument inside, so there's no need of expanding the argument before passing to it... nevertheless I'm not sure if this behavior the guaranteed... so I add \exp_args:Nx just in case.
4
  • Thank you for your answer. Can you give a LaTeX solution? I've tried adding \usepackage{expl3} and compiling with LaTeX but it does not work.
    – Colas
    Jun 12, 2022 at 18:43
  • @Colas expl3 is a LaTeX solution and part of the kernel for the last two years. One could help you better if you added more information than "does not work".
    – Skillmon
    Jun 12, 2022 at 21:06
  • My distribution is too old I think. I have to put \usepackage{expl3} but still there is an error: Undefined control sequence. \nameNewTheoremCapitalized ->\str_uppercase:f . I'll try download a newer version of expl3.
    – Colas
    Jun 12, 2022 at 21:30
  • 1
    @Colas don't only update to a newer version of expl3 (that won't work, I'm afraid). Just update to a newer TeX Live version. Alternatively, put the following after \ExplSyntaxOn: \cs_generate_variant:Nn \str_uppercase:n { f }.
    – Skillmon
    Jun 13, 2022 at 9:33
1

You can use the TeX primitive \uppercase directly, but this is still not expandable, so we have to trick a bit. \createTheorem@a is used to get the first character, and calls \createTheorem@b after the first character was already upper-cased, and puts the name back together.

\documentclass{article}

\usepackage{amsmath}

\makeatletter
\long\def\createTheorem@a#1#2\end
  {\uppercase{\createTheorem@b{#1}}{#2}}
\newcommand\createTheorem@b[2]{\newtheorem{#1#2}}
\newcommand{\createTheorem}[2]
{% 
  \newtheorem{#1}{#2}%
  \createTheorem@a#1\end{#2}%
}
\makeatother

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi}
This is a test.
\end{defi}

\begin{Defi}
This is a test.
\end{Defi}

\end{document}
3
  • Thanks, it works fine. I would to do the same trick with a command \myCommand{} which takes one argument. What would be the syntax to create a command \myCommandWithCapital{}? Thanks
    – Colas
    Jun 12, 2022 at 22:06
  • @Colas Not sure what you mean -- nevertheless if the question is sufficiently different consider asking a new question instead. (by the way you might want to read the TeXbook to learn some TeX programming and understand this answer.)
    – user202729
    Jun 13, 2022 at 0:32
  • 1
    @Colas, the solution is the same. Just use \newtheorem{#1}[WHATEVER]{#2} in \createTheorem and \newtheorem{#1#2}[WHATEVER] in \createTheorem@b.
    – Skillmon
    Jun 13, 2022 at 9:41

You must log in to answer this question.

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