1

I am wondering if you can "reopen" an environment to extend its definition, similar to how in programming languages like Ruby you can reopen a class/module anywhere in your code and extend its definition.

So for example, say you have this in one part of your document:

\newenvironment{myenv}{
  \newcommand\a{}
}{}

Then later on in the document you do this:

\reopenenvironment{myenv}{
  \newcommand\b{}
}{}

That way the end result is this:

\newenvironment{myenv}{
  \newcommand\a{}
}{}

\reopenenvironment{myenv}{
  \newcommand\b{}
}{}

Which should be functionally equivalent to:

\newenvironment{myenv}{
  \newcommand\a{}
  \newcommand\b{}
}{}

Wondering if anything like that exists in Latex. The reasoning is say you have a class with some generic definitions in it. You may want to reuse a specific diagram in various formats a few times, but it doesn't warrant adding it to the class definition. Instead you would just define it inline in your document and use it where right there where needed.

Another variation of this question (or another way this could potentially be accomplished) is by adding a new conditional block to an existing command. So say we had \a as in:

\newenvironment{myenv}{
  \newcommand\a[1]{
    \ifthenelse{\equal{##1}{\string foo}}
      {\typeout{foo}}
      {}
  }
}{}

Then you could extend the definition like this at runtime perhaps:

\reopenenvironment{myenv}{
  \reopencommand\a[1]{
    \ifthenelse{\equal{##1}{\string bar}}
      {\typeout{bar}}
      {}
    \super{}
  }
}{}

That way you can extend it at runtime so you can keep the API:

\begin{myenv}
  \a{foo}
  \a{bar}
\end{myenv}

Wondering if anything like this exists or if there is a normal way to accomplish this with latex.

I would like to be able to do the following:

\begin{athing}{label=baz}
  \stuff
  \stuff
  \stuff
  \stuff
\end{athing}

And then have it usable as:

\begin{myenv}
  \a{baz}
\end{myenv}

Maybe this could somehow be done with a local key/value store. That is,

kvstore = {
  foo: athing
  bar: athing
  baz: athing
}

\newcommand\a[1]{
  kvstore[##1]
}

Maybe that sort of thing is possible, that would be another solution if it was possible.

So to summarize, I would like to be able to have an API:

myapi{somelabela}
myapi{somelabelb}
...

Such that it can be extended at runtime with more definitions. The 3 approaches outlined here are just initial thoughts, I am new to latex. Thank you so much for your help.

2
  • please always provide a complete small test document. For example your initial environment has \newcommand\a which will already generate errors as \a is a predefined command in latex, so the initial environment does not work so it's hard to test extending it. Mar 23, 2018 at 12:56
  • It sounds like you want to use LaTeX in a not-so-LaTeX-y way - which is not going to be very pleasant :) For your first suggestion: this is easy with \AtEndEnvironment from the etoolbox package.
    – Marijn
    Mar 23, 2018 at 14:12

1 Answer 1

1

LaTeX3 (expl3) actually has a nice interface for working with token lists, which would have more or less the functionality you are looking for.

Edit: Realized that my (previously) first approach, wasn't really canonical. This is much better and less hacky:

In LaTeX I suspect that the canonical approach would be using macro hooks, or more specifically \g@addto@macro. This is how \AtBeginDocument works!

\makeatletter
\def\somehook{hello}
\g@addto@macro\somehook{ world}
\somehook %<- prints hello world
\makeatother

The \begin{myenv} command actually triggers the macro \myenv that is defined when you do \newenvironment. Thus:

\makeatletter
\newenvironment{myenv}{hello}{}
\g@addto@macro\myenv{ world}
\begin{myenv}
  !
\end{myenv}
\makeatother

Which prints hello world!


Here is my less canonical approach:

However you can, do it more or less yourself in plain TeX: One "hack" you can do then is

\newenvironment{myenv}{Hello}{}
\let\oldMyenv = \myenv
\def\myenv{\oldMyenv world}
\begin{myenv}
!
\end{myenv}

Which prints Hello world !. This could then be generalized to

\makeatletter
\def\removebs#1{\if#1\@backslashchar\else#1\fi}
\def\macname#1{\expandafter\removebs\string#1}
\def\reopencommand#1#2{
  \def\mname{\macname{#1}}
  \let\oldCommand#1
  \expandafter\gdef\csname \mname\endcsname{\oldCommand #2}
}
\def\hello{hello}
\reopencommand{\hello}{ world}
\hello
\makeatother
5
  • Cool! Would love to see how expl3 does it too :)
    – Lance
    Mar 23, 2018 at 19:05
  • Take a look here: texdev.net/2012/01/22/… Mar 23, 2018 at 19:30
  • Just made a huge update with \g@addto@macro, so you might want to look through it again. Don't for get to accept answer if it satisfied your question :) Mar 23, 2018 at 19:37
  • I would like to see the latex3 way of accomplishing this, with \NewDocumentEnvironment and such if possible :)
    – Lance
    Mar 25, 2018 at 22:37
  • What I was thinking about was not a built in function to do this, but the way they have builtins to work with token-lists: \tl_put_right:Nn and \tl_put_left:Nn, where \tl_put_right:Nn is basically defined as \protected\long\def\tl_put_right:Nn#1#2{\edef#1{\unexpanded\expandafter #1\unexpanded{#2}}. I can expand on it a little further a little later :) Mar 26, 2018 at 8:28

You must log in to answer this question.

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