2

I recently asked How can I migrate commands and environments from LaTeX2e to LaTeX3? [XeTeX]

While that question is good, the answer is likely quite complex and would take a some time to effectively answer (at the time of writing, there are no answers, however, there are a couple of helpful comments).

This question addresses one of the speed bumps I ran into on the road to LaTeX3.

Using xparse LaTeX3 syntax, I am defining:

  1. a command holding a value (functions as variable)
  2. a user command to reset that value
  3. a conditional statement using xparse's \IfEq

Syntax for \IfEq:

\IfEq{〈stringA〉}{〈stringB〉}{〈true〉}{〈false〉}

From the xparse manual:

There are very rare occasion when it may be useful to create functions using a fully expandable argument grabber. To support this, xparse can create expandable functions as well as the usual robust ones. This imposes a number of restrictions on the nature of the arguments accepted by a function, and the code it implements. This facility should only be used when absolutely necessary; if you do not understand when this might be, do not use these functions!

Note there is a typo in version "Released 2014/11/25": *occasions*

Updated Code

From my understanding, \jkoclass needs to be expanded, but will not be expanded with \NewDocumentCommand. Should I be using \DeclareExpandableDocumentCommand?

I realized that my example code was not written the way it should have been when I initially opened the question. Here is the code that I indented:

\documentclass{article}
\usepackage{xparse}
\usepackage{xstring}
\DeclareExpandableDocumentCommand{\jkoclass}{}{I}
\NewDocumentCommand{\jkosetclass}{ m }{\RenewDocumentCommand{\jkoclass}{}{#1}}

\NewDocumentCommand{\jkoimagepath}{}{
    \IfEq{\jkoclass}{I}
        {Value is I}
        {Value is NOT I}
    }
\begin{document}
\jkoimagepath{} (should result in: Value is I)

\jkosetclass{II}
\jkoimagepath{} (should result in: Value is NOT I)
\end{document}

enter image description here

Original Question Code

\documentclass{article}
\usepackage{xparse}
\usepackage{xstring}
\NewDocumentCommand{\jkoclass}{ m }{I}
\NewDocumentCommand{\setjkoclass}{ m }{\RenewDocumentCommand{\jkoclass}{m}{#1}} 
\IfEq{\jkoclass}{I} %<-- \jkoclass is protected automatically by the xparse definition and will therefore not be expand as desired.
  {Class is I}
  {Class is II}
\begin{document}
\setjkoclass{II}
\jkoclass{}
\end{document}
  • Well, you should use xparse for user level macros, and then expl3 for internal macros. – yo' Oct 29 '15 at 11:32
  • @yo' And I quote regarding \DeclareExpandableDocumentCommand "This command is used to create a document-level functions" xparse Released 2014/11/25 p.10 – Jonathan Komar Oct 29 '15 at 12:41
2

You're taking the wrong approach; you can certainly have a user level command \jkoclass that prints something, but if what it prints is variable data, this data should be allocated its own variable.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

% allocate a (global) variable
\tl_new:N \g_macmadness_jko_class_tl

% initialize the value
\tl_gset:Nn \g_macmadness_jko_class_tl { I }

% define a user level command for printing the value
\NewDocumentCommand{\jkoclass}{}
 {
  \tl_use:N \g_macmadness_jko_class_tl
 }

% define a user level command for changing the value
\NewDocumentCommand{\setjkoclass}{m}
 {
  \tl_gset:Nn \g_macmadness_jko_class_tl { #1 }
 }

\ExplSyntaxOff

Suppose now you want to define a new user level command for printing something that depends on the variable to contain I or not.

Add, in the programming environment,

\NewDocumentCommand{\jkoclassifI}{}
 {
  \tl_if_eq:VnTF \g_macmadness_jko_class_tl { I }
   { Class~is~I }     % true branch
   { Class~is~not~I } % false branch
 }
\cs_generate_variant:Nn \tl_if_eq:nnTF { V }

The last instruction is for making available in the programming environment a variant of the token list equality check function that takes as its first argument a token list variable.

Spaces in output in the programming environment must be specified by ~, because ordinary spaces are ignored.

  • Ok, thanks for the tip. The original code I posted was flawed, and I have since fixed it. Is it still the wrong approach? After thinking about it, I realized that my question could have been generalized as: Does a command stay "unprotected"/"expandable" once it is made "unprotected"/"expandable"? I was hoping to address confusing regarding DeclareExpandableDocumentCommand. – Jonathan Komar Oct 29 '15 at 13:18
  • It is also very important that the command I use that actually contains the text (or in my actually case, a path for includegraphics) stays the same throughout all documents. This is because the class names could change in the future (a theoretical assumption to make code live longer :-) – Jonathan Komar Oct 29 '15 at 13:28
  • @macmadness86 Sorry, I can only repeat that you're using the wrong approach. You should never use a user level command as a container. What's wrong with my macros, that I believe are doing exactly what you ask in the edit of the question? – egreg Oct 29 '15 at 13:32
  • Don't misunderstand me, there is nothing wrong with your macros. They work great and you explained them well with comments. I was just trying to understand the concept of protected and unprotected as it applies to xparse and DeclareExpandableDocumentCommand. Your answer implies that the answer to my question is between "no" and "unclear" (because I took the wrong approach altogether). "...is it one of those times when I should use an expandable xparse command?" – Jonathan Komar Oct 29 '15 at 13:43
  • 1
    @macmadness86 One of the main points of expl3 is in the separation between “performing actions” and “storing data” (functions and variables, in common terminology). User level commands should always be functions, maybe for retrieving data from variables. If you notice, \DeclareExpandableDocumentCommand is described with “There are very rare occasion when it may be useful to create functions using a fully-expandable argument grabber.” – egreg Oct 29 '15 at 14:11

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.