xkeyval `boolkey` setting is persistent across macro calls: scope leak?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
4
down vote

favorite
1












I thought that keyval arguments to macros were supposed to be confined in their macro scope, but the following code:



documentclassreport

usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%

makeatother

begindocument

myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless

enddocument


produces:



unexpected behaviour



Why? Am I missing something?

Is there a way to get this default behaviour working regardless of previous calls to the macro?







share|improve this question
















  • 3




    There is no group in myCommand. So the scope of the code in myCommand is the same for all invocations in the example. You can add a group yourself with begingroup and endgroup.
    – moewe
    Sep 3 at 10:38











  • @moewe Oh, so you mean it is my responsibility to close the scope of myCommand. This works indeed, thanks :) Is an extra pair of equivalent to begingroup endgroup?
    – iago-lito
    Sep 3 at 10:47






  • 2




    remember that this is a macro expansion language not a functional programming language, macro definitions are essentially just expanded inline and there is no scope associated with them.
    – David Carlisle
    Sep 3 at 11:24










  • @DavidCarlisle That is true. When we get into concepts like "optional default keyworded arguments", it is easy to tend to forget XD
    – iago-lito
    Sep 3 at 11:26







  • 2




    @iago-lito it's a "uniquely interesting" macro expansion language:-) for your other question if being used for grouping is more or less the same as begingroupendgroup unless you are in math mode, but can be used for more things, eg delimiting arguments that begingroup can not be used for, so it depends....
    – David Carlisle
    Sep 3 at 11:28














up vote
4
down vote

favorite
1












I thought that keyval arguments to macros were supposed to be confined in their macro scope, but the following code:



documentclassreport

usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%

makeatother

begindocument

myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless

enddocument


produces:



unexpected behaviour



Why? Am I missing something?

Is there a way to get this default behaviour working regardless of previous calls to the macro?







share|improve this question
















  • 3




    There is no group in myCommand. So the scope of the code in myCommand is the same for all invocations in the example. You can add a group yourself with begingroup and endgroup.
    – moewe
    Sep 3 at 10:38











  • @moewe Oh, so you mean it is my responsibility to close the scope of myCommand. This works indeed, thanks :) Is an extra pair of equivalent to begingroup endgroup?
    – iago-lito
    Sep 3 at 10:47






  • 2




    remember that this is a macro expansion language not a functional programming language, macro definitions are essentially just expanded inline and there is no scope associated with them.
    – David Carlisle
    Sep 3 at 11:24










  • @DavidCarlisle That is true. When we get into concepts like "optional default keyworded arguments", it is easy to tend to forget XD
    – iago-lito
    Sep 3 at 11:26







  • 2




    @iago-lito it's a "uniquely interesting" macro expansion language:-) for your other question if being used for grouping is more or less the same as begingroupendgroup unless you are in math mode, but can be used for more things, eg delimiting arguments that begingroup can not be used for, so it depends....
    – David Carlisle
    Sep 3 at 11:28












up vote
4
down vote

favorite
1









up vote
4
down vote

favorite
1






1





I thought that keyval arguments to macros were supposed to be confined in their macro scope, but the following code:



documentclassreport

usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%

makeatother

begindocument

myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless

enddocument


produces:



unexpected behaviour



Why? Am I missing something?

Is there a way to get this default behaviour working regardless of previous calls to the macro?







share|improve this question












I thought that keyval arguments to macros were supposed to be confined in their macro scope, but the following code:



documentclassreport

usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%

makeatother

begindocument

myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless

enddocument


produces:



unexpected behaviour



Why? Am I missing something?

Is there a way to get this default behaviour working regardless of previous calls to the macro?









share|improve this question











share|improve this question




share|improve this question










asked Sep 3 at 10:33









iago-lito

610411




610411







  • 3




    There is no group in myCommand. So the scope of the code in myCommand is the same for all invocations in the example. You can add a group yourself with begingroup and endgroup.
    – moewe
    Sep 3 at 10:38











  • @moewe Oh, so you mean it is my responsibility to close the scope of myCommand. This works indeed, thanks :) Is an extra pair of equivalent to begingroup endgroup?
    – iago-lito
    Sep 3 at 10:47






  • 2




    remember that this is a macro expansion language not a functional programming language, macro definitions are essentially just expanded inline and there is no scope associated with them.
    – David Carlisle
    Sep 3 at 11:24










  • @DavidCarlisle That is true. When we get into concepts like "optional default keyworded arguments", it is easy to tend to forget XD
    – iago-lito
    Sep 3 at 11:26







  • 2




    @iago-lito it's a "uniquely interesting" macro expansion language:-) for your other question if being used for grouping is more or less the same as begingroupendgroup unless you are in math mode, but can be used for more things, eg delimiting arguments that begingroup can not be used for, so it depends....
    – David Carlisle
    Sep 3 at 11:28












  • 3




    There is no group in myCommand. So the scope of the code in myCommand is the same for all invocations in the example. You can add a group yourself with begingroup and endgroup.
    – moewe
    Sep 3 at 10:38











  • @moewe Oh, so you mean it is my responsibility to close the scope of myCommand. This works indeed, thanks :) Is an extra pair of equivalent to begingroup endgroup?
    – iago-lito
    Sep 3 at 10:47






  • 2




    remember that this is a macro expansion language not a functional programming language, macro definitions are essentially just expanded inline and there is no scope associated with them.
    – David Carlisle
    Sep 3 at 11:24










  • @DavidCarlisle That is true. When we get into concepts like "optional default keyworded arguments", it is easy to tend to forget XD
    – iago-lito
    Sep 3 at 11:26







  • 2




    @iago-lito it's a "uniquely interesting" macro expansion language:-) for your other question if being used for grouping is more or less the same as begingroupendgroup unless you are in math mode, but can be used for more things, eg delimiting arguments that begingroup can not be used for, so it depends....
    – David Carlisle
    Sep 3 at 11:28







3




3




There is no group in myCommand. So the scope of the code in myCommand is the same for all invocations in the example. You can add a group yourself with begingroup and endgroup.
– moewe
Sep 3 at 10:38





There is no group in myCommand. So the scope of the code in myCommand is the same for all invocations in the example. You can add a group yourself with begingroup and endgroup.
– moewe
Sep 3 at 10:38













@moewe Oh, so you mean it is my responsibility to close the scope of myCommand. This works indeed, thanks :) Is an extra pair of equivalent to begingroup endgroup?
– iago-lito
Sep 3 at 10:47




@moewe Oh, so you mean it is my responsibility to close the scope of myCommand. This works indeed, thanks :) Is an extra pair of equivalent to begingroup endgroup?
– iago-lito
Sep 3 at 10:47




2




2




remember that this is a macro expansion language not a functional programming language, macro definitions are essentially just expanded inline and there is no scope associated with them.
– David Carlisle
Sep 3 at 11:24




remember that this is a macro expansion language not a functional programming language, macro definitions are essentially just expanded inline and there is no scope associated with them.
– David Carlisle
Sep 3 at 11:24












@DavidCarlisle That is true. When we get into concepts like "optional default keyworded arguments", it is easy to tend to forget XD
– iago-lito
Sep 3 at 11:26





@DavidCarlisle That is true. When we get into concepts like "optional default keyworded arguments", it is easy to tend to forget XD
– iago-lito
Sep 3 at 11:26





2




2




@iago-lito it's a "uniquely interesting" macro expansion language:-) for your other question if being used for grouping is more or less the same as begingroupendgroup unless you are in math mode, but can be used for more things, eg delimiting arguments that begingroup can not be used for, so it depends....
– David Carlisle
Sep 3 at 11:28




@iago-lito it's a "uniquely interesting" macro expansion language:-) for your other question if being used for grouping is more or less the same as begingroupendgroup unless you are in math mode, but can be used for more things, eg delimiting arguments that begingroup can not be used for, so it depends....
– David Carlisle
Sep 3 at 11:28










1 Answer
1






active

oldest

votes

















up vote
6
down vote



accepted










Macro definitions don't add a level of grouping themselves, so everything you do in the macro code "leaks out" and just happens in the scope the macro is called in. The idea is that calling somemacro defined with newcommand is the same as pasting the contents of the code argument at that place (without the surrounding braces).



For example



documentclassarticle
usepackagexcolor

newcommand*mygreen[1]%
colorgreen#1

begindocument
Not green

mygreenthis is green

but so is this...

again black
enddocument


The first and last line are black, the second and third line green.



yields two lines of green text because mygreen does not have scope restrictions that would prevent it from applying to the following line. The last line is outside the scope mygreen was called in, so it is black again.



The simple solution is to add begingroup...endgroup to make your settings local to the macro call.



documentclassreport
usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
begingroup
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%
endgroup

makeatother

begindocument
myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless
enddocument


not bold, **bold**, not bold, not bold






share|improve this answer






















  • Interesting. So it is my responsibility to close my macro scope. Cheers :)
    – iago-lito
    Sep 3 at 10:49






  • 2




    @iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
    – moewe
    Sep 3 at 10:51










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',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f449098%2fxkeyval-boolkey-setting-is-persistent-across-macro-calls-scope-leak%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
6
down vote



accepted










Macro definitions don't add a level of grouping themselves, so everything you do in the macro code "leaks out" and just happens in the scope the macro is called in. The idea is that calling somemacro defined with newcommand is the same as pasting the contents of the code argument at that place (without the surrounding braces).



For example



documentclassarticle
usepackagexcolor

newcommand*mygreen[1]%
colorgreen#1

begindocument
Not green

mygreenthis is green

but so is this...

again black
enddocument


The first and last line are black, the second and third line green.



yields two lines of green text because mygreen does not have scope restrictions that would prevent it from applying to the following line. The last line is outside the scope mygreen was called in, so it is black again.



The simple solution is to add begingroup...endgroup to make your settings local to the macro call.



documentclassreport
usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
begingroup
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%
endgroup

makeatother

begindocument
myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless
enddocument


not bold, **bold**, not bold, not bold






share|improve this answer






















  • Interesting. So it is my responsibility to close my macro scope. Cheers :)
    – iago-lito
    Sep 3 at 10:49






  • 2




    @iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
    – moewe
    Sep 3 at 10:51














up vote
6
down vote



accepted










Macro definitions don't add a level of grouping themselves, so everything you do in the macro code "leaks out" and just happens in the scope the macro is called in. The idea is that calling somemacro defined with newcommand is the same as pasting the contents of the code argument at that place (without the surrounding braces).



For example



documentclassarticle
usepackagexcolor

newcommand*mygreen[1]%
colorgreen#1

begindocument
Not green

mygreenthis is green

but so is this...

again black
enddocument


The first and last line are black, the second and third line green.



yields two lines of green text because mygreen does not have scope restrictions that would prevent it from applying to the following line. The last line is outside the scope mygreen was called in, so it is black again.



The simple solution is to add begingroup...endgroup to make your settings local to the macro call.



documentclassreport
usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
begingroup
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%
endgroup

makeatother

begindocument
myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless
enddocument


not bold, **bold**, not bold, not bold






share|improve this answer






















  • Interesting. So it is my responsibility to close my macro scope. Cheers :)
    – iago-lito
    Sep 3 at 10:49






  • 2




    @iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
    – moewe
    Sep 3 at 10:51












up vote
6
down vote



accepted







up vote
6
down vote



accepted






Macro definitions don't add a level of grouping themselves, so everything you do in the macro code "leaks out" and just happens in the scope the macro is called in. The idea is that calling somemacro defined with newcommand is the same as pasting the contents of the code argument at that place (without the surrounding braces).



For example



documentclassarticle
usepackagexcolor

newcommand*mygreen[1]%
colorgreen#1

begindocument
Not green

mygreenthis is green

but so is this...

again black
enddocument


The first and last line are black, the second and third line green.



yields two lines of green text because mygreen does not have scope restrictions that would prevent it from applying to the following line. The last line is outside the scope mygreen was called in, so it is black again.



The simple solution is to add begingroup...endgroup to make your settings local to the macro call.



documentclassreport
usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
begingroup
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%
endgroup

makeatother

begindocument
myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless
enddocument


not bold, **bold**, not bold, not bold






share|improve this answer














Macro definitions don't add a level of grouping themselves, so everything you do in the macro code "leaks out" and just happens in the scope the macro is called in. The idea is that calling somemacro defined with newcommand is the same as pasting the contents of the code argument at that place (without the surrounding braces).



For example



documentclassarticle
usepackagexcolor

newcommand*mygreen[1]%
colorgreen#1

begindocument
Not green

mygreenthis is green

but so is this...

again black
enddocument


The first and last line are black, the second and third line green.



yields two lines of green text because mygreen does not have scope restrictions that would prevent it from applying to the following line. The last line is outside the scope mygreen was called in, so it is black again.



The simple solution is to add begingroup...endgroup to make your settings local to the macro call.



documentclassreport
usepackagexkeyval

% Define a custom command option using `boolkey`
makeatletter
define@boolkeymyCommandoption[true] % one boolean option
newcommandmyCommand[2]%
begingroup
setkeysmyCommand#1%
ifoption%
textbf#2%
else%
#2%
fi%
endgroup

makeatother

begindocument
myCommandnot bold % default behaviour is not to bold

myCommand[option]bold % explicitly set option to bold

myCommandnot bold % fail! default behaviour was expected!

myCommand[option=false]not bold % workaround that makes the "default" concept useless
enddocument


not bold, **bold**, not bold, not bold







share|improve this answer














share|improve this answer



share|improve this answer








edited Sep 3 at 10:56

























answered Sep 3 at 10:48









moewe

75k797285




75k797285











  • Interesting. So it is my responsibility to close my macro scope. Cheers :)
    – iago-lito
    Sep 3 at 10:49






  • 2




    @iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
    – moewe
    Sep 3 at 10:51
















  • Interesting. So it is my responsibility to close my macro scope. Cheers :)
    – iago-lito
    Sep 3 at 10:49






  • 2




    @iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
    – moewe
    Sep 3 at 10:51















Interesting. So it is my responsibility to close my macro scope. Cheers :)
– iago-lito
Sep 3 at 10:49




Interesting. So it is my responsibility to close my macro scope. Cheers :)
– iago-lito
Sep 3 at 10:49




2




2




@iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
– moewe
Sep 3 at 10:51




@iago-lito Pretty much. Although I would say that it would also be your responsibility to open and close a new scope if you want one. The default behaviour just does not change the scope at all.
– moewe
Sep 3 at 10:51

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f449098%2fxkeyval-boolkey-setting-is-persistent-across-macro-calls-scope-leak%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

What does second last employer means? [closed]

Installing NextGIS Connect into QGIS 3?

One-line joke