4

I've cobbled together the \basis macro which sets and gets a hidden/internal length \b@sis. It is meant to work as follows :

  1. Calling \basis returns the value of \b@sis
  2. Calling \basis{} sets \b@sis to the default value (The current font size \f@size) and
  3. Calling \basis{1ex} sets the \b@sis to the specified length.

2 and 3 work but 1 does not always return the value as expected. I can't use \basis within TikZ as a length for instance nor can I show it's value using \the\basis or \showthe\basis. I also tried prefixing \expandafterto the previous two "the" commands with no effect. Below is the code I have so far

\documentclass{standalone}
\usepackage{luatex85}

\usepackage{xparse}
\usepackage{ifthen}
\usepackage{xifthen}
\usepackage{tikz}
\usepackage{booktabs}

\makeatletter
\newlength{\b@sis}
\newlength{\length}
\setlength{\length}{2pt}
\setlength{\b@sis}{2pt}
\ProvideDocumentCommand{\basis}{g}{%
 \IfNoValueTF{#1}{%
  \b@sis}{%
  \ifthenelse{\isempty{#1}}%
  {\setlength{\b@sis}{\f@size pt}%
   \setlength{\length}{\f@size pt}}%
  {\setlength{\b@sis}{#1}%
   \setlength{\length}{#1}}}}%
\newcommand{\showbasis}{\the\b@sis}
\makeatother

\begin{document}
\begin{tabular}{|l|r|c|c|}                                                   % The following calls fail
\toprule
No response  & \basis        \showbasis & \tikz \draw circle(0.5*\length);            \\%& \tikz \draw circle(0.5*\basis); \\
\midrule
Sets default & \basis{}      \showbasis & \basis{}\tikz \draw circle(0.5*\length);    \\%& \tikz \draw circle(0.5*\basis); \\
\midrule
Sets Value   & \basis{1ex}   \showbasis & \basis{1ex}\tikz \draw circle(0.5*\length); \\%& \tikz \draw circle(0.5*\basis); \\
\bottomrule
\end{tabular}
\end{document}

its output looks as follows

enter image description here

My belief is that the \IfNoValueTF is not being expanded when there is no argument and that the expected length not returned. Is there some means of expanding it to return the internal length or is there perhaps a better means fordoing this.

I see \ProvideDocumentCommand allows for an l argument, perhaps I should be using this within my definition ? e.g. is there a change \basis is reading ahead to the first non-whitespace character, the xparse manual implies this might be the case.

Update

Egreg clearly has the better solution but I only saw it after David Carlisle responded and I had messed about with it some more. The interface I got to used \basis and \basis[VALUE] to set the value and \basis* to retrieve it. This is really bad practice though and is certainly not what star is for.

\ProvideDocumentCommand{\basis}{s o}{%
 \IfBooleanTF{#1}
  {\the\b@sis}
  {\IfNoValueTF{#2}{%
    \setlength{\b@sis}{\f@size pt}%
    \setlength{\length}{\f@size pt}}
   {\setlength{\b@sis}{#2}%
    \setlength{\length}{#2}}}
  }%
  • Do you mean I should use \IfNoValueTF{\the#1}{...}{...} or \IfNoValueTF{#1}{\the\b@sis}{...} ? I just tried both, uncommenting the \tikz ... circle(\b@sis); parts and compiling the file. The first dies with missing number treated as zero. The latter with Missing \endcsname inserted and a hint, \l__xpars_processor_int, it fails in xparse. – Carel May 18 '17 at 14:56
  • 1
    although it could be fixed, I'd strongly advise against that user interface as it breaks all latex syntax guidelines. {} should be mandatory arguments, no standard latex command sometimes takes {} and sometimes not ('g' is something of an aberration intended for experimenting with interfaces not matching latex2e) , also it is rather strange to use the same command to both set and retrieve the length. Why not have \setbasis that takes an argument and \basis to retrieve the current value that does not take an argument? – David Carlisle May 18 '17 at 16:10
  • Hmm... I'll commit to the \setbasis and \basis interface, but I am curious as to how \basis might substitute for \length. I'm starting to get a grip on writing my own macros, for quite some time they've largely been an enigma to me, I think it's due to a lack of understanding of the TeX primitives. – Carel May 18 '17 at 16:38
1

A command defined with an optional g argument is not expandable, so you cannot use \basis without argument in an expansion context, such as

\draw circle(0.5*\basis)

It's surely better, as suggested, to split the calls between setting the variable and using it. And you can use the full power of expl3 to get more efficient code.

\documentclass[border=4pt]{standalone}
\usepackage{luatex85}

\usepackage{xparse}
\usepackage{tikz}
\usepackage{booktabs}

\ExplSyntaxOn
\dim_new:N \l_carel_basis_dim
\dim_set:Nn \l_carel_basis_dim { 2pt }

\NewDocumentCommand{\setbasis}{O{\use:c {f@size} pt}}
 {
  \dim_set:Nn \l_carel_basis_dim { #1 }
 }

\NewExpandableDocumentCommand{\basis}{}{\dim_use:N \l_carel_basis_dim}
\ExplSyntaxOff

\begin{document}
\begin{tabular}{lrcc}
\toprule
Initial value & \basis & \tikz \draw circle(0.5*\basis); \\
\midrule
Sets default & \setbasis\basis & \setbasis\tikz \draw circle(0.5*\basis); \\
\midrule
Sets Value   & \setbasis[1ex]\basis & \setbasis[1ex]\tikz \draw circle(0.5*\basis); \\
\bottomrule
\end{tabular}
\end{document}

enter image description here

1

The posted code runs without error and produces what I'd expect, however you do not say what you expect it to do.

The user interface using the same command to both set and retrieve is very confusing and perhaps that is the source of the confusion.

In the second column in the 2nd and 3rd rows you set the length but in the first row you have the rather odd construct

\basis        \showbasis

\basis expands to a use of the internal length and \showbasis expands to \the applied to that length.

if you change it to

\basis        \showbasis\showbasis 

so if \b@sis is 2pt as it is set initially then

\basis        \showbasis

is

\b@sis        \the\b@sis

which expands to

 \b@sis 2pt

so sets \b@sis to the value 2pt that it had already.

Adding a second \showbasis as I did prints the 2pt to the table,

enter image description here

then you see that the value is 2pt hence the small circle.

and if you just have \basis on the cell on its own you get a missing number error as it is the assignment of a length, with no supplied value.

  • That makes far more sense, I assumed that due to g a \basis on it's own would utilize the default value. I also didn't realize I was looping the assignment. Does \basis in \tikz circle (\basis); try to set the value rather then use it ? – Carel May 18 '17 at 16:45
  • I awarded the answer to Egreg but wanted to thank you for your assistance. – Carel May 18 '17 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.