2

When the initial values are not set and the arguments are empty, the current values in the variables are used, not necessarily the .initial:n ones.

.initial:n only sets the values once at point of use, without adding any way to reset those values later.

Is the situation described considered defective ? Should one actually disallow the use of the current values and reset every time a command gets called ?

\documentclass{article}

\ExplSyntaxOn

% Define a new key-value family \keys_define:nn { mymodule } { width .dim_set:N = \l_mymodule_width_dim, %%width .initial:n = 34pt, width .default:n = 10pt,

height .dim_set:N = \l_mymodule_height_dim, %%height .initial:n = 34pt, height .default:n = 10pt,

margin .dim_set:N = \l_mymodule_margin_dim, %%margin .initial:n = 34pt, margin .default:n = 10pt, }

% Command to use the keys \NewDocumentCommand{\setdimensions} { O{} } { % Use the dimensions in your document or perform other actions \fbox { \keys_set:nn { mymodule } { #1 } \begin{tabular}{ll} Width: & \dim_use:N \l_mymodule_width_dim \ Height: & \dim_use:N \l_mymodule_height_dim \ Margin: & \dim_use:N \l_mymodule_margin_dim \end{tabular} } }

\ExplSyntaxOff

\begin{document}

% Example usage With custom values:

\setdimensions[% width = 8cm, height = 4cm, margin = 1.5cm, ]

With initial values:

\setdimensions

With default values:

\setdimensions[width,height,margin]

\end{document}

Ragonese
  • 171
  • 4
  • 2
    we can't tell you want you want to do whether you want to allow document defaults or force a reset every time, You can do either., If you want every use to start from normalised settings do \keys_set:nn { mymodule } { width = 8cm, height = 4cm, margin = 1.5cm} \keys_set:nn { mymodule } { #1 } – David Carlisle Mar 01 '24 at 11:53
  • without adding any way to reset those values later. is of course incorrect you can set them at any time using \keys_set:nn that is exactly what that command does. – David Carlisle Mar 01 '24 at 11:54
  • 1
    Your prefix With initial values: is misleading, it would be better to say: With current values: as the initial values are not reset, your default version will just use whatever the current values of the keys are. – David Carlisle Mar 01 '24 at 11:56
  • there is nothing special about an empty argument here, each key is considered separately the issue iher you set a key or not, the argument is only empty as you set no keys. – David Carlisle Mar 01 '24 at 12:13
  • I wonder whether on should group the \keys_set:nn { mymodule } { #1 } command as { \keys_set:nn { mymodule } { #1 } } or not. – Ragonese Mar 01 '24 at 20:03
  • well then it will do nothing if you just use the standard .dim_set:N storage as all the local settings will be discarded before you use them, – David Carlisle Mar 01 '24 at 20:17
  • the key=value stuff is just surface syntax, it doesn't change the basic nature of tex groups. you need to use a command in the scope it is defined, {\def\foo{x} \foo } not (as you just suggested) {\def\foo{x}} \foo – David Carlisle Mar 01 '24 at 20:19

2 Answers2

2

I modified your example to show two variants A (your version) which picks up the current setttings for any key you don't set, and B which normalises all keys so the current settings are not used.

enter image description here

\documentclass{article}

\ExplSyntaxOn

% Define a new key-value family \keys_define:nn { mymodule } { width .dim_set:N = \l_mymodule_width_dim, %%width .initial:n = 34pt, width .default:n = 10pt,

height .dim_set:N = \l_mymodule_height_dim, height .initial:n = 34pt, height .default:n = 10pt,

margin .dim_set:N = \l_mymodule_margin_dim, %%margin .initial:n = 34pt, margin .default:n = 10pt, }

% Command to use the keys \NewDocumentCommand{\setdimensionsA} { O{} } { % Use the dimensions in your document or perform other actions \fbox { \keys_set:nn { mymodule } { #1 } \begin{tabular}{ll}AAA\ Width: & \dim_use:N \l_mymodule_width_dim \ Height: & \dim_use:N \l_mymodule_height_dim \ Margin: & \dim_use:N \l_mymodule_margin_dim \end{tabular} } }

\NewDocumentCommand{\setdimensionsB} { O{} } { % Use the dimensions in your document or perform other actions \fbox { \keys_set:nn {mymodule} { width = 100pt, height = 200pt, margin = 300pt, } \keys_set:nn { mymodule } { #1 } \begin{tabular}{ll}BBB\ Width: & \dim_use:N \l_mymodule_width_dim \ Height: & \dim_use:N \l_mymodule_height_dim \ Margin: & \dim_use:N \l_mymodule_margin_dim \end{tabular} } }

\NewDocumentCommand\setmymodulekeys{m}{ \keys_set:nn { mymodule } { #1 }}

\ExplSyntaxOff

\begin{document}

% Example usage With custom values:

\setdimensionsA[% width = 8cm, height = 4cm, margin = 1.5cm, ]

\setdimensionsB[% width = 8cm, height = 4cm, margin = 1.5cm, ]

With current values:

\setdimensionsA

\setdimensionsB

With default values:

\setdimensionsA[width,height,margin]

\setdimensionsB[width,height,margin]

Change current values in the current document scope

\setmymodulekeys{width=5pt,height=5pt,margin=5pt}

With new current values:

\setdimensionsA

\setdimensionsB

\end{document}

You can use both styles in a single command. for example in \includegraphics it rarely makes sense to pick up a current value for the file name, it needs to be specified each time but people often globally set width to some fraction of \textwidth if they want all images the same width.

David Carlisle
  • 757,742
  • In essence, there exist circumstances where implementations A and B are appropriate. There is no reason to always favour one over the other. – Ragonese Mar 01 '24 at 13:58
  • Is it a common occurrence to have a command to set the keys as is done by \setmymodulekeys ? – Ragonese Mar 01 '24 at 14:04
  • yes. \hypersetup in hyperref, \sisetup in siunitx, ... in graphicx I don't as global settings less commn but I document \setkeys{Gin}{...} which is the same thing. @Ragonese – David Carlisle Mar 01 '24 at 14:10
  • @Ragonese yes and you can choose per key, in B I reset all three but I could just have reset margin and then margin would act like B and be set per call but height and width would be set like A and pick up current document setting. – David Carlisle Mar 01 '24 at 14:12
2

Default and initial values are different animals.

With .default:n you specify what value is supplied if the key is called without any value.

With .initial:n you specify the value that the key has, well, initially.

A common way to work with key-value items is to set the keys in a group, so when the group is closed, the initial value will be reset, but this is not always possible.

Your analysis is flawed by the fact that you set the keys inside an \fbox, which makes an implicit group.

Let's see the two possible strategies to keep initial values.

Strategy 1 – Grouping

\documentclass{article}

\ExplSyntaxOn

% Define a new key-value family \keys_define:nn { mymodule } { width .dim_set:N = \l_mymodule_width_dim, width .initial:n = 34pt, width .default:n = 10pt,

height .dim_set:N = \l_mymodule_height_dim, height .initial:n = 34pt, height .default:n = 10pt,

margin .dim_set:N = \l_mymodule_margin_dim, margin .initial:n = 34pt, margin .default:n = 10pt, }

% Command to use the keys \NewDocumentCommand{\setdimensions} { O{} } { % Use the dimensions in your document or perform other actions \group_begin: \keys_set:nn { mymodule } { #1 } \begin{tabular}[t]{ll} Width: & \dim_use:N \l_mymodule_width_dim \ Height: & \dim_use:N \l_mymodule_height_dim \ Margin: & \dim_use:N \l_mymodule_margin_dim \end{tabular} \group_end: }

\ExplSyntaxOff

\begin{document}

% Example usage With custom values:

\setdimensions[ width = 80pt, height = 40pt, margin = 20pt, ]

\bigskip

With initial values:

\setdimensions

\bigskip

With default values:

\setdimensions[width,height,margin]

\end{document}

enter image description here

You see that in the second call the initial values are used.

Strategy 2 – Without grouping

If grouping is not possible or not convenient, you can precompile the initial values and use them before setting the new values.

\documentclass{article}

\ExplSyntaxOn

% Define a new key-value family \keys_define:nn { mymodule } { width .dim_set:N = \l_mymodule_width_dim, width .default:n = 10pt,

height .dim_set:N = \l_mymodule_height_dim, height .default:n = 10pt,

margin .dim_set:N = \l_mymodule_margin_dim, margin .default:n = 10pt, }

\tl_new:N \l_mymodule_initial_tl \keys_precompile:nnN { mymodule } { width=34pt, height=34pt, margin=34pt } \l_mymodule_initial_tl

% Command to use the keys \NewDocumentCommand{\setdimensions} { O{} } { % Use the dimensions in your document or perform other actions \tl_use:N \l_mymodule_initial_tl \keys_set:nn { mymodule } { #1 } \begin{tabular}[t]{ll} Width: & \dim_use:N \l_mymodule_width_dim \ Height: & \dim_use:N \l_mymodule_height_dim \ Margin: & \dim_use:N \l_mymodule_margin_dim \end{tabular} }

\ExplSyntaxOff

\begin{document}

% Example usage With custom values:

\setdimensions[ width = 80pt, height = 40pt, margin = 20pt, ]

\bigskip

With initial values:

\setdimensions

\bigskip

With default values:

\setdimensions[width,height,margin]

\end{document}

The output is the same as before.

egreg
  • 1,121,712
  • Thusly, for the sake of clarity, would one recommend not to set the keys inside the \fbox ? – Ragonese Mar 01 '24 at 15:17
  • @Ragonese Not at all. I suggest to use one of those two strategies. The \fbox in your example just makes things unclear. – egreg Mar 01 '24 at 15:44
  • You recommend to group the call \keys_set:nn { mymodule } { #1 }. Seen the possibility suggested by @David to use normalised settings \keys_set:nn { mymodule } { width = 8cm, height = 4cm, margin = 1.5cm} \keys_set:nn { mymodule } { #1 }. The latter seems a superior solution. @egreg Would you agree ? – Ragonese Mar 01 '24 at 21:51
  • @Ragonese David's suggestion is the same as strategy 2, only less efficient. Whether using strategy 1 or 2 depends on the application. – egreg Mar 01 '24 at 22:02
  • That is right, it is the same as your strategy 2. – Ragonese Mar 01 '24 at 22:13
  • @Ragonese See https://tex.stackexchange.com/a/695825/4427 for an example – egreg Mar 01 '24 at 22:17
  • When you group you temporarily change \l_mymodule_width_dim, \dim_use:N \l_mymodule_height_dim and \l_mymodule_margin_dim. Without affecting the actual values stored in them. – Ragonese Mar 01 '24 at 22:25
  • @Ragonese What are you saying? Of course the stored value changes, but the previous one is restored at the end of the group. – egreg Mar 01 '24 at 22:47