Although I appreciate David's answers they seem not to grapple with the design question I asked. Therefore I will attempt to answer this myself using the understanding I've gained from our discussions.
Let's start from the premise that delimited arguments are meant to do exactly what they appear to do: grab arguments but ignore certain surrounding and intervening text. It doesn't matter whether the goal is to actually perform text processing or simply use unusual bracing conventions. I claim that:
It is necessary to have a mechanism to prevent the argument scanner from finding certain expressions that would otherwise constitute a delimited argument;
It is logical that this mechanism is to wrap the affected text in braces;
It is consistent with undelimited arguments to remove those braces;
It is furthermore simplest to do it that way, in that the workaround required to defeat the action in point 3 is easier than the workaround required to produce it if the braces aren't removed.
About point 1: of course such a mechanism is required, or else text that might appear as a delimiter could never appear in an argument (and I know that Knuth is irked by that sort of thing because of his objections to certain verbatim-printing techniques in Appendix D of the TeXbook).
About point 2: as David says in his first answer, there's no other established mechanism in TeX to group things (braces are the grouping characters). It is, furthermore, how we group undelimited arguments as well, so this is an issue of consistency.
About point 3: the key point here is that undelimited arguments are not actually treated any differently than delimited arguments! The description makes the delimited ones sound special, but actually, in the question, I summarized the behavior of argument-grabbing in a perfectly neutral way: arguments are grabbed up until the next delimiter, which is then removed. Undelimited arguments have empty delimiters, that's all.
About point 4: okay, just having a logical reason to do something is not a practical justification for doing it, and my question describes a logical reason for not doing it. It would help to have a logical reason not to do the alternative. So suppose braces were not removed from delimited arguments; then you would be forced by point 1 to add them occasionally and have to get rid of them. How would you do that? There are three cases to take care of (#1
= the argument):
(a): #1 = abc...
(b): #1 = {abc...}
(c): #1 = {abc}{...}
Bear in mind that abc...
can contain nested groups, so your solution has to respect nesting. Therefore, you either have to implement a brace-parser within TeX, or you have to use some primitive that respects nesting. For the solution to be expandable you have to use \def
or \edef
. So: you need to \def
ine a macro capable of stripping the outer braces from (b) but no braces from (c), and not altering (a). Here is a macro that handles (b) and (c), but not (a), using some simple utility macros from LaTeX:
\def\stripbraces#1#2\@nil{%
% #1 is undelimited, so has its braces removed. If there is no #2, that is good.
\ifx\relax#2%
\expandafter\@firstoftwo
% #2 never has its braces removed, even if it's a single group.
\else
\expandafter\@secondoftwo
\fi
{#1}{{#1}#2}%
}
You use it as \stripbraces...\@nil
and it removes the outer braces from ...
. This is under the assumption that delimited arguments don't have their braces removed. Alas, if the text had two or more tokens but no braces to begin, then its first token gets braced.
Now, it is possible to use \futurelet
(i.e. \@ifnextchar
) to figure out if #1
begins with a brace, but that's not expandable. Here is an expandable version inspired by my trickery in this answer, as summarized in this one:
\def\findbrace#1#{%
% The brace is immediately after the macro
\ifx\relax#1%
\expandafter\@firstoftwo
% The next token is not a brace
\else
\expandafter\@secondoftwo
\fi
{\stripbraces}{\remove@nil#1}%
}
\def\remove@nil#1\@nil{#1\@gobble}
Used, of course, as \findbrace...\@nil{}
, and you have to modify \stripbraces
also to \@gobble
the dummy braces you put after \@nil
. These two macros together will catch (a), (b), and (c) as they should.
The alternative to this workaround is the one described in David's second answer: just prepend, say, \empty
to your delimited text and then it will never be surrounded by braces, yet has the same expansion. This is considerably less tricky, to say the least.
I suppose the combination of logical consistency and avoiding extreme trickiness is a good reason to take the route that TeX follows in the real world, though I would like to observe that, since my workaround does exist, the alternative wouldn't have been unacceptable (though possibly unworkable until someone figured it out). And it's not like TeX is exactly averse to trickiness as it is, but by that logic, the present situation with David's workaround is fine too. So I didn't say that.
\def\macro#1{...}
. I'm asking about macros of the form\def\macro#1\pgfeov{...}
, where#1
is anything, possibly multiple groups, that goes until the token\pgfeov
. My complaint is that almost all the time,#1
is taken to be the literal text between\macro
and\pgfeov
; however, if#1
consists of a single brace group, those braces are removed.\def\macro{\macro@\empty}
and\def\macro@#1\pgfeov{\expandafter\macro@@\expandafter{#1}}
. One case where removing braces could be useful is optional arguments in LaTeX2e, where you can "hide]
behind braces", e.g.,\section[{Some [bracketed] text}]{Title}
, without ending up with spurious braces in the argument later.