I am struggling to control expansion in code recorded with ltproperties. In the following example, I am trying to record the body of an environment as stated, without expansion (so as if with \exp_not:n). Of course, to work with ltproperties it needs to first be stored in a variable, so I use \exp_not:V on the variable in the fourth argument of \property_new:nnnn.
\documentclass{article}
\ExplSyntaxOn
\tl_new:N \l__recordenv_contents_tl
\property_new:nnnn { recordenv/contents } { now } { }
{ \exp_not:V \l__recordenv_contents_tl }
\NewDocumentEnvironment{recordenv}{ m +b }
{
\tl_set:Nn \l__recordenv_contents_tl { #2 }
\tl_show:N \l__recordenv_contents_tl
\property_record:nn { #1-recordenv } { recordenv/contents }
}
{}
\ExplSyntaxOff
\begin{document}
\section{First section}
\begin{recordenv}{foo}
some text and \thesection
\end{recordenv}
\section{Second section}
\end{document}
If I check the log, the tl variable contains what I want:
> \l__recordenv_contents_tl=some text and \thesection
However the aux file contains
\relax
\@writefile{toc}{\contentsline {section}{\numberline {1}First section}{1}{}\protected@file@percent }
\new@label@record{foo-recordenv}{{recordenv/contents}{some text and 2}}
\@writefile{toc}{\contentsline {section}{\numberline {2}Second section}{1}{}\protected@file@percent }
\gdef \@abspage@last{1}
So when written to the aux, the body is still being expanded since \thesection becomes a number. Furthermore, this expansion is happening at shipout since the number \thesection expands to is 2, not 1 as you'd expect since the property was set with now.
Now, I thought maybe this was the same issue as in this question I asked about expansion in \addtocontents. There the issue was that two separate expansions were happening so adding an extra \exp_not:n was necessary. However, \exp_not:n { \exp_not:V \l__recordenv_contents_tl } just leads to an empty argument in the aux so I assume that's not what's happening here. I also tried \exp_not:o { \l__recordenv_contents_tl } but the effect is the same as with \exp_not:V.
My questions are
- why is there expansion happening on the tl variable after being V-expanded, and
- why is this second expansion happening at shipout?
Added
I think I now understand why \exp_not:V alone can't work the way I want, and why \exp_not:n { \exp_not:V <tlvar> } fails. The content is expanded once at definition, stripping the \exp_not:n, then expanded again when writing to the file during shipout at which time <tlvar> is empty. Is this correct? Looking at the ltproperties code, I am still confused why \iow_shipout_x:Nx is used in \property_record:nn for all properties, even those with setpoint now.
\thesectionat the time the property is stored by using\exp_not:V. If you just remove it, you'll get{{recordenv/contents}{some text and 1}}as expected (as I'd expect, at least). Off-topic, are you sure trying to store arbitrary content as a property in you aux file is the best method to store such content? Some pitfalls there... – gusbrs Jan 31 '24 at 02:51some text and \thesectionas the value of your property in your aux file, for that you'd need\property_new:nnnn { recordenv/contents } { now } { } { \tl_to_str:V \l__recordenv_contents_tl }, but be really careful there... I wouldn't recommend it. Again, the question sounds like an XY problem and that this is not quite the right tool for the purpose. – gusbrs Jan 31 '24 at 02:53texdoc tex-by-topicsection "12.6.3 Expansion and\write". – gusbrs Jan 31 '24 at 03:20ltpropertiesand just read the first couple of pages of documentation, so take this with a pinch of salt: isn't the point ofltpropertiesto record the expansion (e.g.1) and retrieve it elsewhere (e.g.1at shipout)? It seems odd to pick this tool to record the non-expansion. What am I misunderstanding? – cfr Jan 31 '24 at 04:01\thesectionis a great example of why you actually want to expand it in place. As it is, if the MWE did what the OP claims to want,\thesectionwould give the value at the place the reference is made which makes no sense. That's why I think the MWE is over simplified and we still don't know what the actual problem is (XY so far). – gusbrs Jan 31 '24 at 04:14\exp_not:n{#1}where#1is the env body, then reading those in at begindocument and storing in macros so they can be referenced anywhere in the document. This question is just to see if I can do the same thing with ltproperties, then I'll benchmark to see which approach is faster. The ltproperties approach has the benefit of not writing to a new file – mbert Jan 31 '24 at 04:18\tl_to_str:Vdoes seem to suit my needs. I am aware of catcode issues with what I'm doing. Are there other downsides? – mbert Jan 31 '24 at 04:22\thesectionwas artificial and not instructive for the first question. I used it only to express confusion in the second question about why it's being expanded at shipout when the property is set withnow– mbert Jan 31 '24 at 04:23\tl_to_str:Vbut, regardless, you still have to deal with the difference between catcodes when the argument is read and when the .aux file is read... Also, the time things expand is critical to the results, as the\thesectionshows. Furthermore, you may find trouble in control expansion at reading time (https://github.com/latex3/latex2e/issues/1194). Etc., etc. So, I'm still saying, are you really sure about this the way to go for whatever you are trying to do?... – gusbrs Jan 31 '24 at 04:27expandforrecordenvthat expands the recorded contents with a\protected@edefor\text_expand:nor something else. But having the option allows flexibility for environments where I may want the recorded content intentionally unexpanded so that it depends on its context or, say, the definition of some macro at the time the retrieving macro is called – mbert Jan 31 '24 at 04:33ltpropertiescode, but I'd presume\iow_shipout_x:Nxis used because it is just one label, and it may potentially contain ashipoutproperty, so you can't use an immediate write. The difference between anowand ashipoutproperty is then whether the contents are expanded immediately by other means.zrefdoes have a\zref@wrapper@immediate, but you need to be sure noshipoutproperties are in the list to use it... And I'm not sureltpropertieshas an equivalent construct (yet?). – gusbrs Jan 31 '24 at 10:50\iow_shipout_x:Nxis simply an error which is already corrected in the development code: https://github.com/latex3/latex2e/issues/1200 – Ulrike Fischer Jan 31 '24 at 12:57\immediatewhich\protected@writestill isn't. – gusbrs Jan 31 '24 at 13:03ltpropertiesto check if it is faster than your current approach of writing to a separate file. Probably not, since the.auxis read twice per compilation. – gusbrs Jan 31 '24 at 14:33.auxfile at all, or any external file for that matter. Seepostnoteswhich does something of the sort for end notes. – gusbrs Jan 31 '24 at 14:41ltpropertiesor using a dedicated file, the complications are similar, so... a matter of choice. – gusbrs Jan 31 '24 at 14:46