Joseph Wright skrev:
> Hello all,
>
> As promised yesterday, I'd like to discuss finalising xparse.
[snip]
> Several questions have come up about xparse. At the most basic level,
> the idea of using something like xparse rather than \def
Well, it's more a replacement for \newcommand and friends than for \def...
> (with things
> like \@ifstar, \@ifnextchar, etc.) is a good "good thing". So it is a
> question of picking the best form for xparse.
>
> The idea of using one letter per argument keeps the input simple but
> does cost in power. However, I think that, for reasons I'll outline in a
> bit, it works.
For roughly the same reason as single letters work in tabular/array
column specifiers, I'd say.
> The current system uses modifiers for \long arguments.
> In xparse-alt,
I'll have to take a look at that (but not tonight).
I should perhaps point out that I've also explored some variations on
the xparse theme (Jan 2008, in a package I called xdoc2l3 -- see
http://abel.math.umu.se/~lars/xdoc/), but back then I didn't get much
response to the questions that required *decisions* (and then I got
distracted by other projects). I will mention the issues I recall at
suitable locations below.
> I've explored the alternative idea that lower-case
> letters are always used for short arguments, and upper-case for \long ones:
>
> \DeclareDocumentCommand \foo { o m } % Both short
> \DeclareDocumentCommand \foo { O M } % Both \long
> \DeclareDocumentCommand \foo { o M } % Optional short, mandatory \long
Seems like a good idea -- a modifier for long/short was one thing I
didn't get around to doing, as it seemed rather messy.
> If you compare xparse and xparse-alt, you'll also find I've tried to
> simplify the input somewhat. I've allowed optional modifiers to some
> letters, to include a default input:
>
> \DeclareDocumentCommand \foo { o m } % Optional argument with no default
> \DeclareDocumentCommand \foo { o[default] m } % now has a default!
>
> which keeps the number of letters down and, I hope, is clear enough.
Optional arguments of argument specifiers?!? My feeling is that
optional, star-type, etc. arguments should be considered user-level
syntactic sugar, and that the programming APIs should rather stick with
mandatory arguments and signals like \NoValue. \DeclareDocumentCommand
could be user-level enough that optional arguments make sense, but
there is the alternative of having it be
\DeclareDocumentCommand \foo { o{\NoValue} m }
% Optional argument with no default (returns \NoValue)
\DeclareDocumentCommand \foo { o{default} m }
% now has a default!
Recall that \newcommand and friends require you to specify a default
value for the optional argument whenever there is one.
> The current xparse implementation lets you create your own specifier
> letters. This is probably very risky: what if two packages use the same
> letter? I'd drop this idea.
Agreed. An analogy with array package definitions of new column
specifiers fails because there it is usually the document author who
would make the definition, thus confining the definition to code under
the control of that author, whereas with xparse it would be arbitrary
package authors that don't have such confinement.
I believe the ability to compose more basic "particles" into an
argument specifier -- a key feature in the system I deviced -- would
furthermore reduce the demand for naming new specifiers; why invent a
name for it if you can write down the steps that define it?
> Related, the current xparse also allows
> comparison using different methods (by charcode, by meaning, etc.). This
> is important for things like testing for a star:
>
> \DeclareDocumentCommand \foo { s o m } % test for * as first arg.
>
> Will has pointed out it would be best to only test by charcode: looking
> for a star should do exactly that. By dropping the "different test
> methods" idea, things are also simplified.
No objection from me.
> Thinking about catcode-sensitive input, most cases can be handled by the
> e-TeX tools we have available. For true verbatim input, that obviously
> does not work, but I feel that truing to "crowbar" verbatim input xparse
> is a mistake. Almost all user functions are not verbatim, and the
> particular issues for those that are, I think, better handled by hand.
> (The way that xparse works means that it absorbs arguments before
> passing them to the code you program.) I also suspect that xparse
> handling of verbatim will never be reliable enough for general use.
Is that a yes or no to my "harmless character sequences"? These can
handle data like URLs which might prompt people to go verbatim, but
they aren't implemented using \catcode changes.
> Will has suggested that we should insist optional arguments follow
> directly on, with no spaces, to mean that:
>
> \foo*{arg} % #1 = TRUE, #2 = "arg"
> and
>
> \foo *{arg} % #1 = FALSE, #2 = "*"
>
> are treated differently.
Bad example. You can't treat these differently, since they tokenise to
the same thing. The motivating example should rather be
\foo{arg}[opt] % #1 = "arg", #2 = "opt"
[Optional arguments] are sometimes seen where there are none.
versus
\foo{arg} % #1 = "arg", #2 = \NoValue
[Optional arguments] are sometimes seen where there are none.
With the LaTeX2e \@ifnextchar that looks past spaces, the latter
example comes out as #1 = "arg", #2 = "Optional arguments".
> The idea here is that it makes LaTeX syntax
> more "regular", useful for translation to other formats. I think he's
> right, but wonder how others see it. The current xparse allows both
> space-skipping and non-space-skipping tests. I'd certainly say we
> should go with only one: either spaces are allowed or they are not.
Since TeX always skips spaces (i) after control sequences whose names
consist of letters and (ii) in front of a mandatory argument, the only
possibility if you want to make it more "regular" for non-TeX parsers
is to skip spaces in front of all kinds of argument. I think that is
the wrong way to go however, as it increases the risk of LaTeX grabbing
text that isn't arguments.
> Finally, the question about expandability of \IfNoValue has been asked
> before. As \DeclareDocumentCommand only ever makes \protected
> functions, I don't think we need to worry. The idea is that the NoValue
> test should be done "early":
>
> \DeclareDocumentCommand \foo { o m } {
> \IfNoValueTF {#1} {
> \int_function_one:n {#2}
> }{
> \int_function_two:nn {#1} {#2}
> }
> }
>
> and not in the internal functions. So the test can never be expanded,
> and there is not an issue (I hope).
There's quite a lot which is wrong with that. First, you presume that
optional arguments are mostly a method of combining two
implementation-level commands into one user-level command; in that
particular case, it would probably be easier to just expose
\int_function_one:n and \int_function_two:nn separately. Second, you
assume that the \IfNoValueTF test will happen close to the command
which takes an optional argument (otherwise protection status becomes
irrelevant), but a great advantage of \NoValue is that it can be passed
around without syntactic difficulties, so the actual test might happen
in a distant helper macro or even completely separate from the \foo
command (if the argument is stored away in a token list). Finally,
you're thinking too imperatively about the whole thing, thus discarding
the possibility of performing such tests at expand-only time.
The following is a short extract from some code I've been using for
years, and which occurs entirely within a \[log in to unmask] Here, I'd
like to switch the idiom "\ifx\NoValue#1\@empty" to ”\IfNoValueTF{#1}":
\LevelSorted{%
#4 \ifx \NoValue#1\@empty
\TD@namespace
\else
\TD@convert@colons #1::\relax
\fi
}{%
\texttt{#3}%
\ifx \NoValue#5\@empty \else\space(#5)\fi, %
\ifx \NoValue#1\@empty
\texttt{\TD@namespace} %
\else\ifx $#1$%
global %
\else
\texttt{\TD@convert@colons #1::\relax} %
\fi\fi \namespacephrase
}%
Good luck rewriting that in imperative style, as a non-expandable
\IfNoValueTF would require (and you seem to prefer!!). Mind you, this
is maybe a third of the full thing being \edef'ed...
>
> ================================================================
>
> That is a long e-mail, I'm afraid.
Nowhere near as long as those I've written on the subject in the past ;-)
> There will probably need to be more
> explanation so that everyone can follow things: ask away. I'd like to
> finalise xparse soon (I need it for siunitx, and I want people to be
> able to test that!).
Other possible xparse features I'd like to see discussed (and recall
right now) are:
* The ability to preprocess (e.g. evaluate as a calc expression)
an argument before handing it to the command body.
* The ability to have arguments assigned to token lists rather
than handed as macro parameters (lets one get around the 9
parameter limit).
Lars Hellström
|