Are all commands with an optional argument fragile?Definitions made with newcommand die after one useIs it possible to use the `substr` package to extract the name of a command, then call that command?Custom commands with optional arguments in section titleOptional argument for newcommand?Are commands defined by newcommand[.][.]. robust?New command with optional argument being first argumentMoving the optional argumentInserting command with optional argument as optional argument ProblemUsing macro with optional argument inside macro with optional argumentNeed Section Digit with Period in TOCgobble optional argument in edeflet on macro defined by newcommand with optional argumentoptional argument
What instances can be solved today by modern solvers (pure LP)?
My players like to search everything. What do they find?
What units are kpts?
Are "confidant" and "confident" homophones?
Creating patterns
how can i make this execution plan more efficient?
Boss has banned cycling to work because he thinks it's unsafe
Why did C++11 make std::string::data() add a null terminating character?
Why is there paternal, for fatherly, fraternal, for brotherly, but no similar word for sons?
Term for a character that only exists to be talked to
Should I increase my 401(k) contributions, or increase my mortgage payments
List comprehensions in Mathematica?
What is the fundamental difference between catching whales and hunting other animals?
Why did moving the mouse cursor cause Windows 95 to run more quickly?
How can I define a very large matrix efficiently?
Why would "dead languages" be the only languages that spells could be written in?
Are there advantages in writing by hand over typing out a story?
Motorcyle Chain needs to be cleaned every time you lube it?
Does a multiclassed wizard start with a spellbook?
Why would a propeller have blades of different lengths?
Did Snape really give Umbridge a fake Veritaserum potion that Harry later pretended to drink?
In the Seventh Seal why does Death let the chess game happen?
Machine Learning Golf: Multiplication
How did שְׁלֹמֹה (shlomo) become Solomon?
Are all commands with an optional argument fragile?
Definitions made with newcommand die after one useIs it possible to use the `substr` package to extract the name of a command, then call that command?Custom commands with optional arguments in section titleOptional argument for newcommand?Are commands defined by newcommand[.][.]. robust?New command with optional argument being first argumentMoving the optional argumentInserting command with optional argument as optional argument ProblemUsing macro with optional argument inside macro with optional argumentNeed Section Digit with Period in TOCgobble optional argument in edeflet on macro defined by newcommand with optional argumentoptional argument
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Here is a discussion of fragile command in LaTeX. And it says that any commands that have an optional argument are fragile, for instance footnote[2]myfoottext
and footnotmyotherfoottext
. I have tried the example below which the commmand b
has an optional parameter but it works without protect
.
documentclassarticle
defb[#1]#2.#2.bf #1
begindocument
tableofcontents
sectionprotectb[one]two %works
sectionb[one]two %also works
enddocument
Here is the code in the .toc
file:
contentsline sectionnumberline 1b [one]two1%
contentsline sectionnumberline 2.t.bf onewo1%
However, it shows the effect of the command protect
.
macros tex-core optional-arguments latex-base fragile
add a comment |
Here is a discussion of fragile command in LaTeX. And it says that any commands that have an optional argument are fragile, for instance footnote[2]myfoottext
and footnotmyotherfoottext
. I have tried the example below which the commmand b
has an optional parameter but it works without protect
.
documentclassarticle
defb[#1]#2.#2.bf #1
begindocument
tableofcontents
sectionprotectb[one]two %works
sectionb[one]two %also works
enddocument
Here is the code in the .toc
file:
contentsline sectionnumberline 1b [one]two1%
contentsline sectionnumberline 2.t.bf onewo1%
However, it shows the effect of the command protect
.
macros tex-core optional-arguments latex-base fragile
7
But the[
...]
-enclosed argument is not optional, it's just delimited by[
...]
, so it's not fragile. And it won't work if you don't use the[
...]
argument.
– Phelype Oleinik
Jun 25 at 14:41
So, what's an optional argument?
– Brooks
Jun 25 at 14:45
3
TeX doesn't actually know about optional arguments. What is done in LaTeX to get the effect of optional arguments, is to check if the the next token is equal to[
usingfuturelet
. If this is the case, another macro is called that absorbs a mandatory argument enclosed in[...]
, similar to your macro. This allows you to change the meaning of a macro depending on whether a certain argument is given or not.
– siracusa
Jun 25 at 15:01
1
Note also that you should useb[one]two
to have it expand to.two.one
instead of.t.onewo
(unless that's what you want, of course :-)
– Phelype Oleinik
Jun 25 at 15:59
add a comment |
Here is a discussion of fragile command in LaTeX. And it says that any commands that have an optional argument are fragile, for instance footnote[2]myfoottext
and footnotmyotherfoottext
. I have tried the example below which the commmand b
has an optional parameter but it works without protect
.
documentclassarticle
defb[#1]#2.#2.bf #1
begindocument
tableofcontents
sectionprotectb[one]two %works
sectionb[one]two %also works
enddocument
Here is the code in the .toc
file:
contentsline sectionnumberline 1b [one]two1%
contentsline sectionnumberline 2.t.bf onewo1%
However, it shows the effect of the command protect
.
macros tex-core optional-arguments latex-base fragile
Here is a discussion of fragile command in LaTeX. And it says that any commands that have an optional argument are fragile, for instance footnote[2]myfoottext
and footnotmyotherfoottext
. I have tried the example below which the commmand b
has an optional parameter but it works without protect
.
documentclassarticle
defb[#1]#2.#2.bf #1
begindocument
tableofcontents
sectionprotectb[one]two %works
sectionb[one]two %also works
enddocument
Here is the code in the .toc
file:
contentsline sectionnumberline 1b [one]two1%
contentsline sectionnumberline 2.t.bf onewo1%
However, it shows the effect of the command protect
.
macros tex-core optional-arguments latex-base fragile
macros tex-core optional-arguments latex-base fragile
edited Jun 26 at 2:25
Phelype Oleinik
30.9k7 gold badges52 silver badges105 bronze badges
30.9k7 gold badges52 silver badges105 bronze badges
asked Jun 25 at 14:38
BrooksBrooks
1998 bronze badges
1998 bronze badges
7
But the[
...]
-enclosed argument is not optional, it's just delimited by[
...]
, so it's not fragile. And it won't work if you don't use the[
...]
argument.
– Phelype Oleinik
Jun 25 at 14:41
So, what's an optional argument?
– Brooks
Jun 25 at 14:45
3
TeX doesn't actually know about optional arguments. What is done in LaTeX to get the effect of optional arguments, is to check if the the next token is equal to[
usingfuturelet
. If this is the case, another macro is called that absorbs a mandatory argument enclosed in[...]
, similar to your macro. This allows you to change the meaning of a macro depending on whether a certain argument is given or not.
– siracusa
Jun 25 at 15:01
1
Note also that you should useb[one]two
to have it expand to.two.one
instead of.t.onewo
(unless that's what you want, of course :-)
– Phelype Oleinik
Jun 25 at 15:59
add a comment |
7
But the[
...]
-enclosed argument is not optional, it's just delimited by[
...]
, so it's not fragile. And it won't work if you don't use the[
...]
argument.
– Phelype Oleinik
Jun 25 at 14:41
So, what's an optional argument?
– Brooks
Jun 25 at 14:45
3
TeX doesn't actually know about optional arguments. What is done in LaTeX to get the effect of optional arguments, is to check if the the next token is equal to[
usingfuturelet
. If this is the case, another macro is called that absorbs a mandatory argument enclosed in[...]
, similar to your macro. This allows you to change the meaning of a macro depending on whether a certain argument is given or not.
– siracusa
Jun 25 at 15:01
1
Note also that you should useb[one]two
to have it expand to.two.one
instead of.t.onewo
(unless that's what you want, of course :-)
– Phelype Oleinik
Jun 25 at 15:59
7
7
But the
[
...]
-enclosed argument is not optional, it's just delimited by [
...]
, so it's not fragile. And it won't work if you don't use the [
...]
argument.– Phelype Oleinik
Jun 25 at 14:41
But the
[
...]
-enclosed argument is not optional, it's just delimited by [
...]
, so it's not fragile. And it won't work if you don't use the [
...]
argument.– Phelype Oleinik
Jun 25 at 14:41
So, what's an optional argument?
– Brooks
Jun 25 at 14:45
So, what's an optional argument?
– Brooks
Jun 25 at 14:45
3
3
TeX doesn't actually know about optional arguments. What is done in LaTeX to get the effect of optional arguments, is to check if the the next token is equal to
[
using futurelet
. If this is the case, another macro is called that absorbs a mandatory argument enclosed in [...]
, similar to your macro. This allows you to change the meaning of a macro depending on whether a certain argument is given or not.– siracusa
Jun 25 at 15:01
TeX doesn't actually know about optional arguments. What is done in LaTeX to get the effect of optional arguments, is to check if the the next token is equal to
[
using futurelet
. If this is the case, another macro is called that absorbs a mandatory argument enclosed in [...]
, similar to your macro. This allows you to change the meaning of a macro depending on whether a certain argument is given or not.– siracusa
Jun 25 at 15:01
1
1
Note also that you should use
b[one]two
to have it expand to .two.one
instead of .t.onewo
(unless that's what you want, of course :-)– Phelype Oleinik
Jun 25 at 15:59
Note also that you should use
b[one]two
to have it expand to .two.one
instead of .t.onewo
(unless that's what you want, of course :-)– Phelype Oleinik
Jun 25 at 15:59
add a comment |
2 Answers
2
active
oldest
votes
The command you defined does not take an optional argument, it takes a delimited argument. If you do:
defb[#1]#2.#2.bf #1
b[one]two
it will work fine, however if you remove the [one]
TeX will throw an error:
defb[#1]#2.#2.bf #1
b two
! Use of b doesn't match its definition.
l.5 b t
wo
?
because when you define a command with defb[#1]#2.#2.bf #1
, TeX expects that when you use b
, the input matches exactly the parameter text (i.e., [#1]#2
), which means that the next token must be [
, and when it is not that error is raised. See here for a brief description of that.
When using just def
none of the arguments are optional! However, let's say you define:
newcommandb[2][--empty--].#2.bf #1
then the command will have 2
arguments, the first of which is optional, and if not given the default value is --empty--
. When you use b
, the defined command does not actually take any argument, but it checks if the next character is a [
. If it is, the command proceeds to use an "inner" b
(let's call it b@opt
), which is defined as you did, with defb@opt[#1]#2.#2.bf #1
. However if you use b
without the following [
, then a b@noopt
is used, which is defined as defb@nooptb@opt[--empty--]
. So after all you end up using b@opt
, but the underlying definition provides the optional argument if you don't give it one.
You can manually define that with:
makeatletter
defb%
@ifnextchar[%
b@optb@noopt%
defb@nooptb@opt[--empty--]
defb@opt[#1]#2.#2.bf #1
makeatother
Now, what makes the optional argument thing “fragile”?
A command is fragile when it can't work properly in an expansion-only context, which is usually when being written to a temporary file, like in section headings as you showed, captions, and the like, but also inside an edef
or, more recently, in expanded
.
It's said that commands with optional arguments are fragile because the mechanism that checks if an optional argument is there (precisely, the @ifnextchar
macro above) usually is fragile. It is possible, under some restrictions, to check for an optional argument expandably, like in xparse
's NewExpandableDocumentCommand
, but usually that's not the case.
Taking the command defined above as example, if you do edeftestb[one]two
(or write
or expanded
) TeX starts expanding from left to right, so the first thing it sees is b
, which is expanded to
@ifnextchar[b@optb@noopt
Next the @ifnextchar
test is expanded to:
letreserved@d=[%
defreserved@ab@opt%
defreserved@bb@noopt%
futurelet@let@token@ifnch
Here the problem appears. let
, def
, and futurelet
aren't expandable, so TeX leaves them as they are, and proceeds expanding the rest. All other macros there will be expanded by TeX, but by doing so the let
and def
will not define reserved@d
and such, but their expansion, and this will make the code not work as intended.
Of course this is just an example, but the basic principle of fragility is that a command that contains non-expandable tokens is being used in an expansion-only context.
How to make a command robust?
Until a couple decades ago the only way to make a command robust was to prevent its expansion with noexpandcommand
, which makes TeX temporarily treat command
as unexpandable and skip it in an expansion-only context. The downside of this is that as soon as the expansion was carried out the noexpand
would disappear and the command would be fragile again.
To circumvent this LaTeX defines protect
and the accompanying macros protected@edef
and protected@write
, which define protect
as defprotectnoexpandprotectnoexpand
. Then, in an expansion-only context protectcommand
will expand to noexpandprotectnoexpandcommand
. TeX will throw both noexpand
s away, temporarily making protectcommand
both unexpandable. If you happened to use the command again, it would continue being robust if you used the protected@...
macros instead of the normal ones.
Commands with optional arguments defined with LaTeX2ε's newcommand
and the like have a different look (but the same machinery underneath). If you define newcommandb[2][--empty--].#2.bf #1
, then b
will actually be protected@testopt b \b --empty--
(that \b
is the command \b
, with two backslashes, not \
then b
). protected@testopt
will use the protect
machinery to test whether it can be safely expanded. If it cannot it will leave protectb
, otherwise it will proceed to use \b
, which contains the actual definition of the command.
All this became easier when ε-TeX introduced the protected
primitive, which allows you to make a macro engine-protected. This means that instead of tricking TeX to noexpand
your macro, you will define the macro as robust with:
protecteddefb%
@ifnextchar[%
b@optb@noopt%
and then TeX itself will know that b
is not supposed to be expanded inside an edef
or write
or expanded
, without additional machinery.
LaTeX2ε doesn't use protected
to define robust macros because of backwards compatibility. LaTeX2ε predates ε-TeX, so the protection mechanism was established much earlier. LaTeX3, for example, dropped the 2ε protection mechanism and uses only protected
to define robust macros.
As a side note, I'd change that definition of yours to:
newcommandmybold[2][--empty--].#2.textbf#1
and use as:
mybold[one]two
I changed the command to mybold
, as one-letter command names are not generally a good idea. I also changed bf
(which is deprecated for decades now) to textbf
and put the second argument in braces, so that the second argument is two
, not just t
.
4
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
you start off by saying commands defined bynewcommand
are fragile but then you correctly explain how such commands are defined in terms ofprotected@testopt
which as its name implies, internally handles theprotect
mechanism, making the defined command robust.
– David Carlisle
Jun 25 at 18:45
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
add a comment |
The information on that page is wrong (or at least outdated, all commands in latex2.09 that had an optional argument were fragile, but latex2e has been available since 1993...)
the example in the question does not define an optional argument but if you change it so that it does, using the facility of newcommand
to define such an argument you will see that the resulting command is robust and this works without error
documentclassarticle
newcommandzb[2][?].#2. textbf#1
begindocument
tableofcontents
sectionzb[one]two %works
zzz
sectionzbthree %also works
zzz
enddocument
If you look at the .toc
file you will see that this did not "blow up" the way a fragile command would, it produces
contentsline sectionnumberline 1zb [one]two1%
contentsline sectionnumberline 2zb three1%
Latex defines zb
here in such a way that the protect
mechanism is used internally so you do not need to explicitly use protect
, so such command are, by definition, robust.
Of the list in that page
All commands that have an optional argument are fragile.
As noted above any commands with optional argument defined by newcommand
(as well as some others) are robust (this has always been the case in LaTeX2e)
Environments delimited by
begin ... end
are fragile.
yes (we might fix that one day)
Display math environment delimited by
[ ... ]
No, [
has been robust since the 2015 release.
Math environment
( ... )
However,$ ... $
is robust
No, (
has been robust since the 2015 release.
Line breaks,
\
No, \
has been robust since the 1994 release
item
commands
Yes.
footnote
commands
Yes.
The list fails to mentionlinebreak
andnolinebreak
, which are still fragile.
– egreg
Jun 26 at 22:06
1
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "85"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f497356%2fare-all-commands-with-an-optional-argument-fragile%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The command you defined does not take an optional argument, it takes a delimited argument. If you do:
defb[#1]#2.#2.bf #1
b[one]two
it will work fine, however if you remove the [one]
TeX will throw an error:
defb[#1]#2.#2.bf #1
b two
! Use of b doesn't match its definition.
l.5 b t
wo
?
because when you define a command with defb[#1]#2.#2.bf #1
, TeX expects that when you use b
, the input matches exactly the parameter text (i.e., [#1]#2
), which means that the next token must be [
, and when it is not that error is raised. See here for a brief description of that.
When using just def
none of the arguments are optional! However, let's say you define:
newcommandb[2][--empty--].#2.bf #1
then the command will have 2
arguments, the first of which is optional, and if not given the default value is --empty--
. When you use b
, the defined command does not actually take any argument, but it checks if the next character is a [
. If it is, the command proceeds to use an "inner" b
(let's call it b@opt
), which is defined as you did, with defb@opt[#1]#2.#2.bf #1
. However if you use b
without the following [
, then a b@noopt
is used, which is defined as defb@nooptb@opt[--empty--]
. So after all you end up using b@opt
, but the underlying definition provides the optional argument if you don't give it one.
You can manually define that with:
makeatletter
defb%
@ifnextchar[%
b@optb@noopt%
defb@nooptb@opt[--empty--]
defb@opt[#1]#2.#2.bf #1
makeatother
Now, what makes the optional argument thing “fragile”?
A command is fragile when it can't work properly in an expansion-only context, which is usually when being written to a temporary file, like in section headings as you showed, captions, and the like, but also inside an edef
or, more recently, in expanded
.
It's said that commands with optional arguments are fragile because the mechanism that checks if an optional argument is there (precisely, the @ifnextchar
macro above) usually is fragile. It is possible, under some restrictions, to check for an optional argument expandably, like in xparse
's NewExpandableDocumentCommand
, but usually that's not the case.
Taking the command defined above as example, if you do edeftestb[one]two
(or write
or expanded
) TeX starts expanding from left to right, so the first thing it sees is b
, which is expanded to
@ifnextchar[b@optb@noopt
Next the @ifnextchar
test is expanded to:
letreserved@d=[%
defreserved@ab@opt%
defreserved@bb@noopt%
futurelet@let@token@ifnch
Here the problem appears. let
, def
, and futurelet
aren't expandable, so TeX leaves them as they are, and proceeds expanding the rest. All other macros there will be expanded by TeX, but by doing so the let
and def
will not define reserved@d
and such, but their expansion, and this will make the code not work as intended.
Of course this is just an example, but the basic principle of fragility is that a command that contains non-expandable tokens is being used in an expansion-only context.
How to make a command robust?
Until a couple decades ago the only way to make a command robust was to prevent its expansion with noexpandcommand
, which makes TeX temporarily treat command
as unexpandable and skip it in an expansion-only context. The downside of this is that as soon as the expansion was carried out the noexpand
would disappear and the command would be fragile again.
To circumvent this LaTeX defines protect
and the accompanying macros protected@edef
and protected@write
, which define protect
as defprotectnoexpandprotectnoexpand
. Then, in an expansion-only context protectcommand
will expand to noexpandprotectnoexpandcommand
. TeX will throw both noexpand
s away, temporarily making protectcommand
both unexpandable. If you happened to use the command again, it would continue being robust if you used the protected@...
macros instead of the normal ones.
Commands with optional arguments defined with LaTeX2ε's newcommand
and the like have a different look (but the same machinery underneath). If you define newcommandb[2][--empty--].#2.bf #1
, then b
will actually be protected@testopt b \b --empty--
(that \b
is the command \b
, with two backslashes, not \
then b
). protected@testopt
will use the protect
machinery to test whether it can be safely expanded. If it cannot it will leave protectb
, otherwise it will proceed to use \b
, which contains the actual definition of the command.
All this became easier when ε-TeX introduced the protected
primitive, which allows you to make a macro engine-protected. This means that instead of tricking TeX to noexpand
your macro, you will define the macro as robust with:
protecteddefb%
@ifnextchar[%
b@optb@noopt%
and then TeX itself will know that b
is not supposed to be expanded inside an edef
or write
or expanded
, without additional machinery.
LaTeX2ε doesn't use protected
to define robust macros because of backwards compatibility. LaTeX2ε predates ε-TeX, so the protection mechanism was established much earlier. LaTeX3, for example, dropped the 2ε protection mechanism and uses only protected
to define robust macros.
As a side note, I'd change that definition of yours to:
newcommandmybold[2][--empty--].#2.textbf#1
and use as:
mybold[one]two
I changed the command to mybold
, as one-letter command names are not generally a good idea. I also changed bf
(which is deprecated for decades now) to textbf
and put the second argument in braces, so that the second argument is two
, not just t
.
4
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
you start off by saying commands defined bynewcommand
are fragile but then you correctly explain how such commands are defined in terms ofprotected@testopt
which as its name implies, internally handles theprotect
mechanism, making the defined command robust.
– David Carlisle
Jun 25 at 18:45
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
add a comment |
The command you defined does not take an optional argument, it takes a delimited argument. If you do:
defb[#1]#2.#2.bf #1
b[one]two
it will work fine, however if you remove the [one]
TeX will throw an error:
defb[#1]#2.#2.bf #1
b two
! Use of b doesn't match its definition.
l.5 b t
wo
?
because when you define a command with defb[#1]#2.#2.bf #1
, TeX expects that when you use b
, the input matches exactly the parameter text (i.e., [#1]#2
), which means that the next token must be [
, and when it is not that error is raised. See here for a brief description of that.
When using just def
none of the arguments are optional! However, let's say you define:
newcommandb[2][--empty--].#2.bf #1
then the command will have 2
arguments, the first of which is optional, and if not given the default value is --empty--
. When you use b
, the defined command does not actually take any argument, but it checks if the next character is a [
. If it is, the command proceeds to use an "inner" b
(let's call it b@opt
), which is defined as you did, with defb@opt[#1]#2.#2.bf #1
. However if you use b
without the following [
, then a b@noopt
is used, which is defined as defb@nooptb@opt[--empty--]
. So after all you end up using b@opt
, but the underlying definition provides the optional argument if you don't give it one.
You can manually define that with:
makeatletter
defb%
@ifnextchar[%
b@optb@noopt%
defb@nooptb@opt[--empty--]
defb@opt[#1]#2.#2.bf #1
makeatother
Now, what makes the optional argument thing “fragile”?
A command is fragile when it can't work properly in an expansion-only context, which is usually when being written to a temporary file, like in section headings as you showed, captions, and the like, but also inside an edef
or, more recently, in expanded
.
It's said that commands with optional arguments are fragile because the mechanism that checks if an optional argument is there (precisely, the @ifnextchar
macro above) usually is fragile. It is possible, under some restrictions, to check for an optional argument expandably, like in xparse
's NewExpandableDocumentCommand
, but usually that's not the case.
Taking the command defined above as example, if you do edeftestb[one]two
(or write
or expanded
) TeX starts expanding from left to right, so the first thing it sees is b
, which is expanded to
@ifnextchar[b@optb@noopt
Next the @ifnextchar
test is expanded to:
letreserved@d=[%
defreserved@ab@opt%
defreserved@bb@noopt%
futurelet@let@token@ifnch
Here the problem appears. let
, def
, and futurelet
aren't expandable, so TeX leaves them as they are, and proceeds expanding the rest. All other macros there will be expanded by TeX, but by doing so the let
and def
will not define reserved@d
and such, but their expansion, and this will make the code not work as intended.
Of course this is just an example, but the basic principle of fragility is that a command that contains non-expandable tokens is being used in an expansion-only context.
How to make a command robust?
Until a couple decades ago the only way to make a command robust was to prevent its expansion with noexpandcommand
, which makes TeX temporarily treat command
as unexpandable and skip it in an expansion-only context. The downside of this is that as soon as the expansion was carried out the noexpand
would disappear and the command would be fragile again.
To circumvent this LaTeX defines protect
and the accompanying macros protected@edef
and protected@write
, which define protect
as defprotectnoexpandprotectnoexpand
. Then, in an expansion-only context protectcommand
will expand to noexpandprotectnoexpandcommand
. TeX will throw both noexpand
s away, temporarily making protectcommand
both unexpandable. If you happened to use the command again, it would continue being robust if you used the protected@...
macros instead of the normal ones.
Commands with optional arguments defined with LaTeX2ε's newcommand
and the like have a different look (but the same machinery underneath). If you define newcommandb[2][--empty--].#2.bf #1
, then b
will actually be protected@testopt b \b --empty--
(that \b
is the command \b
, with two backslashes, not \
then b
). protected@testopt
will use the protect
machinery to test whether it can be safely expanded. If it cannot it will leave protectb
, otherwise it will proceed to use \b
, which contains the actual definition of the command.
All this became easier when ε-TeX introduced the protected
primitive, which allows you to make a macro engine-protected. This means that instead of tricking TeX to noexpand
your macro, you will define the macro as robust with:
protecteddefb%
@ifnextchar[%
b@optb@noopt%
and then TeX itself will know that b
is not supposed to be expanded inside an edef
or write
or expanded
, without additional machinery.
LaTeX2ε doesn't use protected
to define robust macros because of backwards compatibility. LaTeX2ε predates ε-TeX, so the protection mechanism was established much earlier. LaTeX3, for example, dropped the 2ε protection mechanism and uses only protected
to define robust macros.
As a side note, I'd change that definition of yours to:
newcommandmybold[2][--empty--].#2.textbf#1
and use as:
mybold[one]two
I changed the command to mybold
, as one-letter command names are not generally a good idea. I also changed bf
(which is deprecated for decades now) to textbf
and put the second argument in braces, so that the second argument is two
, not just t
.
4
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
you start off by saying commands defined bynewcommand
are fragile but then you correctly explain how such commands are defined in terms ofprotected@testopt
which as its name implies, internally handles theprotect
mechanism, making the defined command robust.
– David Carlisle
Jun 25 at 18:45
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
add a comment |
The command you defined does not take an optional argument, it takes a delimited argument. If you do:
defb[#1]#2.#2.bf #1
b[one]two
it will work fine, however if you remove the [one]
TeX will throw an error:
defb[#1]#2.#2.bf #1
b two
! Use of b doesn't match its definition.
l.5 b t
wo
?
because when you define a command with defb[#1]#2.#2.bf #1
, TeX expects that when you use b
, the input matches exactly the parameter text (i.e., [#1]#2
), which means that the next token must be [
, and when it is not that error is raised. See here for a brief description of that.
When using just def
none of the arguments are optional! However, let's say you define:
newcommandb[2][--empty--].#2.bf #1
then the command will have 2
arguments, the first of which is optional, and if not given the default value is --empty--
. When you use b
, the defined command does not actually take any argument, but it checks if the next character is a [
. If it is, the command proceeds to use an "inner" b
(let's call it b@opt
), which is defined as you did, with defb@opt[#1]#2.#2.bf #1
. However if you use b
without the following [
, then a b@noopt
is used, which is defined as defb@nooptb@opt[--empty--]
. So after all you end up using b@opt
, but the underlying definition provides the optional argument if you don't give it one.
You can manually define that with:
makeatletter
defb%
@ifnextchar[%
b@optb@noopt%
defb@nooptb@opt[--empty--]
defb@opt[#1]#2.#2.bf #1
makeatother
Now, what makes the optional argument thing “fragile”?
A command is fragile when it can't work properly in an expansion-only context, which is usually when being written to a temporary file, like in section headings as you showed, captions, and the like, but also inside an edef
or, more recently, in expanded
.
It's said that commands with optional arguments are fragile because the mechanism that checks if an optional argument is there (precisely, the @ifnextchar
macro above) usually is fragile. It is possible, under some restrictions, to check for an optional argument expandably, like in xparse
's NewExpandableDocumentCommand
, but usually that's not the case.
Taking the command defined above as example, if you do edeftestb[one]two
(or write
or expanded
) TeX starts expanding from left to right, so the first thing it sees is b
, which is expanded to
@ifnextchar[b@optb@noopt
Next the @ifnextchar
test is expanded to:
letreserved@d=[%
defreserved@ab@opt%
defreserved@bb@noopt%
futurelet@let@token@ifnch
Here the problem appears. let
, def
, and futurelet
aren't expandable, so TeX leaves them as they are, and proceeds expanding the rest. All other macros there will be expanded by TeX, but by doing so the let
and def
will not define reserved@d
and such, but their expansion, and this will make the code not work as intended.
Of course this is just an example, but the basic principle of fragility is that a command that contains non-expandable tokens is being used in an expansion-only context.
How to make a command robust?
Until a couple decades ago the only way to make a command robust was to prevent its expansion with noexpandcommand
, which makes TeX temporarily treat command
as unexpandable and skip it in an expansion-only context. The downside of this is that as soon as the expansion was carried out the noexpand
would disappear and the command would be fragile again.
To circumvent this LaTeX defines protect
and the accompanying macros protected@edef
and protected@write
, which define protect
as defprotectnoexpandprotectnoexpand
. Then, in an expansion-only context protectcommand
will expand to noexpandprotectnoexpandcommand
. TeX will throw both noexpand
s away, temporarily making protectcommand
both unexpandable. If you happened to use the command again, it would continue being robust if you used the protected@...
macros instead of the normal ones.
Commands with optional arguments defined with LaTeX2ε's newcommand
and the like have a different look (but the same machinery underneath). If you define newcommandb[2][--empty--].#2.bf #1
, then b
will actually be protected@testopt b \b --empty--
(that \b
is the command \b
, with two backslashes, not \
then b
). protected@testopt
will use the protect
machinery to test whether it can be safely expanded. If it cannot it will leave protectb
, otherwise it will proceed to use \b
, which contains the actual definition of the command.
All this became easier when ε-TeX introduced the protected
primitive, which allows you to make a macro engine-protected. This means that instead of tricking TeX to noexpand
your macro, you will define the macro as robust with:
protecteddefb%
@ifnextchar[%
b@optb@noopt%
and then TeX itself will know that b
is not supposed to be expanded inside an edef
or write
or expanded
, without additional machinery.
LaTeX2ε doesn't use protected
to define robust macros because of backwards compatibility. LaTeX2ε predates ε-TeX, so the protection mechanism was established much earlier. LaTeX3, for example, dropped the 2ε protection mechanism and uses only protected
to define robust macros.
As a side note, I'd change that definition of yours to:
newcommandmybold[2][--empty--].#2.textbf#1
and use as:
mybold[one]two
I changed the command to mybold
, as one-letter command names are not generally a good idea. I also changed bf
(which is deprecated for decades now) to textbf
and put the second argument in braces, so that the second argument is two
, not just t
.
The command you defined does not take an optional argument, it takes a delimited argument. If you do:
defb[#1]#2.#2.bf #1
b[one]two
it will work fine, however if you remove the [one]
TeX will throw an error:
defb[#1]#2.#2.bf #1
b two
! Use of b doesn't match its definition.
l.5 b t
wo
?
because when you define a command with defb[#1]#2.#2.bf #1
, TeX expects that when you use b
, the input matches exactly the parameter text (i.e., [#1]#2
), which means that the next token must be [
, and when it is not that error is raised. See here for a brief description of that.
When using just def
none of the arguments are optional! However, let's say you define:
newcommandb[2][--empty--].#2.bf #1
then the command will have 2
arguments, the first of which is optional, and if not given the default value is --empty--
. When you use b
, the defined command does not actually take any argument, but it checks if the next character is a [
. If it is, the command proceeds to use an "inner" b
(let's call it b@opt
), which is defined as you did, with defb@opt[#1]#2.#2.bf #1
. However if you use b
without the following [
, then a b@noopt
is used, which is defined as defb@nooptb@opt[--empty--]
. So after all you end up using b@opt
, but the underlying definition provides the optional argument if you don't give it one.
You can manually define that with:
makeatletter
defb%
@ifnextchar[%
b@optb@noopt%
defb@nooptb@opt[--empty--]
defb@opt[#1]#2.#2.bf #1
makeatother
Now, what makes the optional argument thing “fragile”?
A command is fragile when it can't work properly in an expansion-only context, which is usually when being written to a temporary file, like in section headings as you showed, captions, and the like, but also inside an edef
or, more recently, in expanded
.
It's said that commands with optional arguments are fragile because the mechanism that checks if an optional argument is there (precisely, the @ifnextchar
macro above) usually is fragile. It is possible, under some restrictions, to check for an optional argument expandably, like in xparse
's NewExpandableDocumentCommand
, but usually that's not the case.
Taking the command defined above as example, if you do edeftestb[one]two
(or write
or expanded
) TeX starts expanding from left to right, so the first thing it sees is b
, which is expanded to
@ifnextchar[b@optb@noopt
Next the @ifnextchar
test is expanded to:
letreserved@d=[%
defreserved@ab@opt%
defreserved@bb@noopt%
futurelet@let@token@ifnch
Here the problem appears. let
, def
, and futurelet
aren't expandable, so TeX leaves them as they are, and proceeds expanding the rest. All other macros there will be expanded by TeX, but by doing so the let
and def
will not define reserved@d
and such, but their expansion, and this will make the code not work as intended.
Of course this is just an example, but the basic principle of fragility is that a command that contains non-expandable tokens is being used in an expansion-only context.
How to make a command robust?
Until a couple decades ago the only way to make a command robust was to prevent its expansion with noexpandcommand
, which makes TeX temporarily treat command
as unexpandable and skip it in an expansion-only context. The downside of this is that as soon as the expansion was carried out the noexpand
would disappear and the command would be fragile again.
To circumvent this LaTeX defines protect
and the accompanying macros protected@edef
and protected@write
, which define protect
as defprotectnoexpandprotectnoexpand
. Then, in an expansion-only context protectcommand
will expand to noexpandprotectnoexpandcommand
. TeX will throw both noexpand
s away, temporarily making protectcommand
both unexpandable. If you happened to use the command again, it would continue being robust if you used the protected@...
macros instead of the normal ones.
Commands with optional arguments defined with LaTeX2ε's newcommand
and the like have a different look (but the same machinery underneath). If you define newcommandb[2][--empty--].#2.bf #1
, then b
will actually be protected@testopt b \b --empty--
(that \b
is the command \b
, with two backslashes, not \
then b
). protected@testopt
will use the protect
machinery to test whether it can be safely expanded. If it cannot it will leave protectb
, otherwise it will proceed to use \b
, which contains the actual definition of the command.
All this became easier when ε-TeX introduced the protected
primitive, which allows you to make a macro engine-protected. This means that instead of tricking TeX to noexpand
your macro, you will define the macro as robust with:
protecteddefb%
@ifnextchar[%
b@optb@noopt%
and then TeX itself will know that b
is not supposed to be expanded inside an edef
or write
or expanded
, without additional machinery.
LaTeX2ε doesn't use protected
to define robust macros because of backwards compatibility. LaTeX2ε predates ε-TeX, so the protection mechanism was established much earlier. LaTeX3, for example, dropped the 2ε protection mechanism and uses only protected
to define robust macros.
As a side note, I'd change that definition of yours to:
newcommandmybold[2][--empty--].#2.textbf#1
and use as:
mybold[one]two
I changed the command to mybold
, as one-letter command names are not generally a good idea. I also changed bf
(which is deprecated for decades now) to textbf
and put the second argument in braces, so that the second argument is two
, not just t
.
edited Jun 26 at 16:48
siracusa
6,6761 gold badge17 silver badges33 bronze badges
6,6761 gold badge17 silver badges33 bronze badges
answered Jun 25 at 15:04
Phelype OleinikPhelype Oleinik
30.9k7 gold badges52 silver badges105 bronze badges
30.9k7 gold badges52 silver badges105 bronze badges
4
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
you start off by saying commands defined bynewcommand
are fragile but then you correctly explain how such commands are defined in terms ofprotected@testopt
which as its name implies, internally handles theprotect
mechanism, making the defined command robust.
– David Carlisle
Jun 25 at 18:45
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
add a comment |
4
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
you start off by saying commands defined bynewcommand
are fragile but then you correctly explain how such commands are defined in terms ofprotected@testopt
which as its name implies, internally handles theprotect
mechanism, making the defined command robust.
– David Carlisle
Jun 25 at 18:45
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
4
4
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
This answer deserves more upvotes!
– Steven B. Segletes
Jun 25 at 16:31
you start off by saying commands defined by
newcommand
are fragile but then you correctly explain how such commands are defined in terms of protected@testopt
which as its name implies, internally handles the protect
mechanism, making the defined command robust.– David Carlisle
Jun 25 at 18:45
you start off by saying commands defined by
newcommand
are fragile but then you correctly explain how such commands are defined in terms of protected@testopt
which as its name implies, internally handles the protect
mechanism, making the defined command robust.– David Carlisle
Jun 25 at 18:45
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
@DavidCarlisle Oops... Fixed. Thanks!
– Phelype Oleinik
Jun 25 at 19:01
add a comment |
The information on that page is wrong (or at least outdated, all commands in latex2.09 that had an optional argument were fragile, but latex2e has been available since 1993...)
the example in the question does not define an optional argument but if you change it so that it does, using the facility of newcommand
to define such an argument you will see that the resulting command is robust and this works without error
documentclassarticle
newcommandzb[2][?].#2. textbf#1
begindocument
tableofcontents
sectionzb[one]two %works
zzz
sectionzbthree %also works
zzz
enddocument
If you look at the .toc
file you will see that this did not "blow up" the way a fragile command would, it produces
contentsline sectionnumberline 1zb [one]two1%
contentsline sectionnumberline 2zb three1%
Latex defines zb
here in such a way that the protect
mechanism is used internally so you do not need to explicitly use protect
, so such command are, by definition, robust.
Of the list in that page
All commands that have an optional argument are fragile.
As noted above any commands with optional argument defined by newcommand
(as well as some others) are robust (this has always been the case in LaTeX2e)
Environments delimited by
begin ... end
are fragile.
yes (we might fix that one day)
Display math environment delimited by
[ ... ]
No, [
has been robust since the 2015 release.
Math environment
( ... )
However,$ ... $
is robust
No, (
has been robust since the 2015 release.
Line breaks,
\
No, \
has been robust since the 1994 release
item
commands
Yes.
footnote
commands
Yes.
The list fails to mentionlinebreak
andnolinebreak
, which are still fragile.
– egreg
Jun 26 at 22:06
1
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
add a comment |
The information on that page is wrong (or at least outdated, all commands in latex2.09 that had an optional argument were fragile, but latex2e has been available since 1993...)
the example in the question does not define an optional argument but if you change it so that it does, using the facility of newcommand
to define such an argument you will see that the resulting command is robust and this works without error
documentclassarticle
newcommandzb[2][?].#2. textbf#1
begindocument
tableofcontents
sectionzb[one]two %works
zzz
sectionzbthree %also works
zzz
enddocument
If you look at the .toc
file you will see that this did not "blow up" the way a fragile command would, it produces
contentsline sectionnumberline 1zb [one]two1%
contentsline sectionnumberline 2zb three1%
Latex defines zb
here in such a way that the protect
mechanism is used internally so you do not need to explicitly use protect
, so such command are, by definition, robust.
Of the list in that page
All commands that have an optional argument are fragile.
As noted above any commands with optional argument defined by newcommand
(as well as some others) are robust (this has always been the case in LaTeX2e)
Environments delimited by
begin ... end
are fragile.
yes (we might fix that one day)
Display math environment delimited by
[ ... ]
No, [
has been robust since the 2015 release.
Math environment
( ... )
However,$ ... $
is robust
No, (
has been robust since the 2015 release.
Line breaks,
\
No, \
has been robust since the 1994 release
item
commands
Yes.
footnote
commands
Yes.
The list fails to mentionlinebreak
andnolinebreak
, which are still fragile.
– egreg
Jun 26 at 22:06
1
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
add a comment |
The information on that page is wrong (or at least outdated, all commands in latex2.09 that had an optional argument were fragile, but latex2e has been available since 1993...)
the example in the question does not define an optional argument but if you change it so that it does, using the facility of newcommand
to define such an argument you will see that the resulting command is robust and this works without error
documentclassarticle
newcommandzb[2][?].#2. textbf#1
begindocument
tableofcontents
sectionzb[one]two %works
zzz
sectionzbthree %also works
zzz
enddocument
If you look at the .toc
file you will see that this did not "blow up" the way a fragile command would, it produces
contentsline sectionnumberline 1zb [one]two1%
contentsline sectionnumberline 2zb three1%
Latex defines zb
here in such a way that the protect
mechanism is used internally so you do not need to explicitly use protect
, so such command are, by definition, robust.
Of the list in that page
All commands that have an optional argument are fragile.
As noted above any commands with optional argument defined by newcommand
(as well as some others) are robust (this has always been the case in LaTeX2e)
Environments delimited by
begin ... end
are fragile.
yes (we might fix that one day)
Display math environment delimited by
[ ... ]
No, [
has been robust since the 2015 release.
Math environment
( ... )
However,$ ... $
is robust
No, (
has been robust since the 2015 release.
Line breaks,
\
No, \
has been robust since the 1994 release
item
commands
Yes.
footnote
commands
Yes.
The information on that page is wrong (or at least outdated, all commands in latex2.09 that had an optional argument were fragile, but latex2e has been available since 1993...)
the example in the question does not define an optional argument but if you change it so that it does, using the facility of newcommand
to define such an argument you will see that the resulting command is robust and this works without error
documentclassarticle
newcommandzb[2][?].#2. textbf#1
begindocument
tableofcontents
sectionzb[one]two %works
zzz
sectionzbthree %also works
zzz
enddocument
If you look at the .toc
file you will see that this did not "blow up" the way a fragile command would, it produces
contentsline sectionnumberline 1zb [one]two1%
contentsline sectionnumberline 2zb three1%
Latex defines zb
here in such a way that the protect
mechanism is used internally so you do not need to explicitly use protect
, so such command are, by definition, robust.
Of the list in that page
All commands that have an optional argument are fragile.
As noted above any commands with optional argument defined by newcommand
(as well as some others) are robust (this has always been the case in LaTeX2e)
Environments delimited by
begin ... end
are fragile.
yes (we might fix that one day)
Display math environment delimited by
[ ... ]
No, [
has been robust since the 2015 release.
Math environment
( ... )
However,$ ... $
is robust
No, (
has been robust since the 2015 release.
Line breaks,
\
No, \
has been robust since the 1994 release
item
commands
Yes.
footnote
commands
Yes.
edited Jun 25 at 19:10
answered Jun 25 at 18:53
David CarlisleDavid Carlisle
513k44 gold badges1163 silver badges1927 bronze badges
513k44 gold badges1163 silver badges1927 bronze badges
The list fails to mentionlinebreak
andnolinebreak
, which are still fragile.
– egreg
Jun 26 at 22:06
1
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
add a comment |
The list fails to mentionlinebreak
andnolinebreak
, which are still fragile.
– egreg
Jun 26 at 22:06
1
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
The list fails to mention
linebreak
and nolinebreak
, which are still fragile.– egreg
Jun 26 at 22:06
The list fails to mention
linebreak
and nolinebreak
, which are still fragile.– egreg
Jun 26 at 22:06
1
1
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
@egreg I noticed later that the page was last updated in 1995 so not surprising it has a latex2.09 flavour
– David Carlisle
Jun 26 at 22:21
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
But it's on the net, so it must be right…
– egreg
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg hmm your answers are on the net as well....
– David Carlisle
Jun 26 at 22:22
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
@egreg soooorry, my original problem is not the titled ques, it is why optional argument is fragile and what's optional argument. thanks for your suggestion.
– Brooks
12 hours ago
add a comment |
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f497356%2fare-all-commands-with-an-optional-argument-fragile%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
7
But the
[
...]
-enclosed argument is not optional, it's just delimited by[
...]
, so it's not fragile. And it won't work if you don't use the[
...]
argument.– Phelype Oleinik
Jun 25 at 14:41
So, what's an optional argument?
– Brooks
Jun 25 at 14:45
3
TeX doesn't actually know about optional arguments. What is done in LaTeX to get the effect of optional arguments, is to check if the the next token is equal to
[
usingfuturelet
. If this is the case, another macro is called that absorbs a mandatory argument enclosed in[...]
, similar to your macro. This allows you to change the meaning of a macro depending on whether a certain argument is given or not.– siracusa
Jun 25 at 15:01
1
Note also that you should use
b[one]two
to have it expand to.two.one
instead of.t.onewo
(unless that's what you want, of course :-)– Phelype Oleinik
Jun 25 at 15:59