Macro losing value when exiting custom environment
Clash Royale CLAN TAG#URR8PPP
up vote
4
down vote
favorite
I'm trying to define my own custom environment, and ran into this problem: When I set a macro inside the environment's start code, that macro loses its value at the end of the environment.
To be more precise, with the following LaTeX code
deffooinit
newenvironmenttest
entering test environment, foo = foo\
deffoobar
updated to foo = foo\
exiting test environment, foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
I get the following output:
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
As you see, the value of the macro seems to reset right at the end of the environment's end code. This poses two questions:
What is going on here?
Is this some kind of local scope with a local macro that shadows the global macro's value? Or is it some other mechanism that I have not yet understood?How can I assign a value to a macro inside an environment in such a way, that I can actually make use of it afterwards?
environments programming
New contributor
add a comment |Â
up vote
4
down vote
favorite
I'm trying to define my own custom environment, and ran into this problem: When I set a macro inside the environment's start code, that macro loses its value at the end of the environment.
To be more precise, with the following LaTeX code
deffooinit
newenvironmenttest
entering test environment, foo = foo\
deffoobar
updated to foo = foo\
exiting test environment, foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
I get the following output:
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
As you see, the value of the macro seems to reset right at the end of the environment's end code. This poses two questions:
What is going on here?
Is this some kind of local scope with a local macro that shadows the global macro's value? Or is it some other mechanism that I have not yet understood?How can I assign a value to a macro inside an environment in such a way, that I can actually make use of it afterwards?
environments programming
New contributor
2
begintest
implicitly starts a group andendtest
ends it. That means that all assignment that happen in your environment are local to the environment. If you usegdeffoobar
the assignment is global and will be available outside the environment as well (and indeed globally).
â moewe
1 hour ago
@moewe Thanks a lot.gdef
seems to be exactly what I need. Would you mind fleshing that out in an answer so that I may vote on it?
â cmaster
1 hour ago
1
On my way......
â moewe
1 hour ago
add a comment |Â
up vote
4
down vote
favorite
up vote
4
down vote
favorite
I'm trying to define my own custom environment, and ran into this problem: When I set a macro inside the environment's start code, that macro loses its value at the end of the environment.
To be more precise, with the following LaTeX code
deffooinit
newenvironmenttest
entering test environment, foo = foo\
deffoobar
updated to foo = foo\
exiting test environment, foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
I get the following output:
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
As you see, the value of the macro seems to reset right at the end of the environment's end code. This poses two questions:
What is going on here?
Is this some kind of local scope with a local macro that shadows the global macro's value? Or is it some other mechanism that I have not yet understood?How can I assign a value to a macro inside an environment in such a way, that I can actually make use of it afterwards?
environments programming
New contributor
I'm trying to define my own custom environment, and ran into this problem: When I set a macro inside the environment's start code, that macro loses its value at the end of the environment.
To be more precise, with the following LaTeX code
deffooinit
newenvironmenttest
entering test environment, foo = foo\
deffoobar
updated to foo = foo\
exiting test environment, foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
begintest
inside environment: foo = foo\
endtest
outside environment: foo = foo\
I get the following output:
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
entering test environment, foo = init
updated to foo = bar
inside environment: foo = bar
exiting test environment, foo = bar
outside environment: foo = init
As you see, the value of the macro seems to reset right at the end of the environment's end code. This poses two questions:
What is going on here?
Is this some kind of local scope with a local macro that shadows the global macro's value? Or is it some other mechanism that I have not yet understood?How can I assign a value to a macro inside an environment in such a way, that I can actually make use of it afterwards?
environments programming
environments programming
New contributor
New contributor
edited 43 mins ago
egreg
685k8418273076
685k8418273076
New contributor
asked 1 hour ago
cmaster
1212
1212
New contributor
New contributor
2
begintest
implicitly starts a group andendtest
ends it. That means that all assignment that happen in your environment are local to the environment. If you usegdeffoobar
the assignment is global and will be available outside the environment as well (and indeed globally).
â moewe
1 hour ago
@moewe Thanks a lot.gdef
seems to be exactly what I need. Would you mind fleshing that out in an answer so that I may vote on it?
â cmaster
1 hour ago
1
On my way......
â moewe
1 hour ago
add a comment |Â
2
begintest
implicitly starts a group andendtest
ends it. That means that all assignment that happen in your environment are local to the environment. If you usegdeffoobar
the assignment is global and will be available outside the environment as well (and indeed globally).
â moewe
1 hour ago
@moewe Thanks a lot.gdef
seems to be exactly what I need. Would you mind fleshing that out in an answer so that I may vote on it?
â cmaster
1 hour ago
1
On my way......
â moewe
1 hour ago
2
2
begintest
implicitly starts a group and endtest
ends it. That means that all assignment that happen in your environment are local to the environment. If you use gdeffoobar
the assignment is global and will be available outside the environment as well (and indeed globally).â moewe
1 hour ago
begintest
implicitly starts a group and endtest
ends it. That means that all assignment that happen in your environment are local to the environment. If you use gdeffoobar
the assignment is global and will be available outside the environment as well (and indeed globally).â moewe
1 hour ago
@moewe Thanks a lot.
gdef
seems to be exactly what I need. Would you mind fleshing that out in an answer so that I may vote on it?â cmaster
1 hour ago
@moewe Thanks a lot.
gdef
seems to be exactly what I need. Would you mind fleshing that out in an answer so that I may vote on it?â cmaster
1 hour ago
1
1
On my way......
â moewe
1 hour ago
On my way......
â moewe
1 hour ago
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
5
down vote
When you define an environment with
newenvironmentenvnamebegincodeendcode
and use it with
beginenvname
body
endenvname
LaTeX roughly executes
begingroup
begincode % as envname
body
endcode % as endenvname
endgroup
That means that all assignments that happen within begincode
, endcode
and bodycode
are local to the group implicit in the environment.
In your case the deffoobar
then applies only to the environment - outside of the environment the original value is restored. You could go all-in with gdef
and make a global assignment:
gdeffoobar
But the effect of a gdef
is truly global and in complicated situations with many groups can be different from a local assignment one scope 'above' the environment.
Some assignments like LaTeX counter operations are always global and don't need additional work to break out of environments, but most other assignments are local and will need something like gdef
to also apply outside of the environment.
Note that you made it easy for me by using def
(which has a global companion gdef
). LaTeX's newcommand
and renewcommand
for example do not have global companions and must be replaced with a gdef
construction.
add a comment |Â
up vote
3
down vote
There are very good reasons why LaTeX opens a group upon entering an environment and closes it at exit.
First reason.
The name of the current environment is saved in the macro @currenvir
; when an end
command occurs, LaTeX can check its argument against the meaning of @currenvir
; if they agree, good, otherwise an error is raised. Then the group can be closed and @currenvir
will regain the meaning it had when begin
was executed.
The alternative would be maintaining a stack, each begin
pushing an item to the stack and each end
popping one. But since grouping is useful for other reasons, there was no point in doing it when LaTeX was born (and computer memory scarce).
Second reason
Several environments are used for special typesetting: consider for instance center
, flushleft
, enumerate
, itemize
and so on.
Each of these environments may set a lot of parameters and here we see that maintaining a stack would become painful; just think to enumerate
nested in itemize
. Not to mention technical difficulties when par
is redefined to do something different from its usual action and maybe this redefinition contains code to redefine par
itself as soon as the modified one is executed.
Grouping ensures that the previous values of the parameters modified by the environment are automatically restored at the environment's end.
By the way, this is a reason why there are no chapter
, section
and so on environments, which might be attractive at first thought: a very long chapter
environment, with many inner environments, could fill the stack memory TeX allocates for restoring values. Again, consider when LaTeX was written, with severe computer memory constraints.
Disadvantages
Look at the code for lrbox
to see how the problem of setting a box in an environment, but its value preserved at endlrbox
is overcome. Interesting code to study, particularly at hboxbegingroupaftergroup
that may surprise at first reading ;-)
It is not possible to define a macro inside an environment so that its value is propagated at the upper level without doing special tricks like the one mentioned; propagating it to two levels above is doubly tricky and so on.
Solution
Use a global definition: gdeffoobar
will propagate the redefinition to all levels. See globalrenewcommand equivalent of globaldef if you want to use LaTeX-like syntax instead, with the usual protections.
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
When you define an environment with
newenvironmentenvnamebegincodeendcode
and use it with
beginenvname
body
endenvname
LaTeX roughly executes
begingroup
begincode % as envname
body
endcode % as endenvname
endgroup
That means that all assignments that happen within begincode
, endcode
and bodycode
are local to the group implicit in the environment.
In your case the deffoobar
then applies only to the environment - outside of the environment the original value is restored. You could go all-in with gdef
and make a global assignment:
gdeffoobar
But the effect of a gdef
is truly global and in complicated situations with many groups can be different from a local assignment one scope 'above' the environment.
Some assignments like LaTeX counter operations are always global and don't need additional work to break out of environments, but most other assignments are local and will need something like gdef
to also apply outside of the environment.
Note that you made it easy for me by using def
(which has a global companion gdef
). LaTeX's newcommand
and renewcommand
for example do not have global companions and must be replaced with a gdef
construction.
add a comment |Â
up vote
5
down vote
When you define an environment with
newenvironmentenvnamebegincodeendcode
and use it with
beginenvname
body
endenvname
LaTeX roughly executes
begingroup
begincode % as envname
body
endcode % as endenvname
endgroup
That means that all assignments that happen within begincode
, endcode
and bodycode
are local to the group implicit in the environment.
In your case the deffoobar
then applies only to the environment - outside of the environment the original value is restored. You could go all-in with gdef
and make a global assignment:
gdeffoobar
But the effect of a gdef
is truly global and in complicated situations with many groups can be different from a local assignment one scope 'above' the environment.
Some assignments like LaTeX counter operations are always global and don't need additional work to break out of environments, but most other assignments are local and will need something like gdef
to also apply outside of the environment.
Note that you made it easy for me by using def
(which has a global companion gdef
). LaTeX's newcommand
and renewcommand
for example do not have global companions and must be replaced with a gdef
construction.
add a comment |Â
up vote
5
down vote
up vote
5
down vote
When you define an environment with
newenvironmentenvnamebegincodeendcode
and use it with
beginenvname
body
endenvname
LaTeX roughly executes
begingroup
begincode % as envname
body
endcode % as endenvname
endgroup
That means that all assignments that happen within begincode
, endcode
and bodycode
are local to the group implicit in the environment.
In your case the deffoobar
then applies only to the environment - outside of the environment the original value is restored. You could go all-in with gdef
and make a global assignment:
gdeffoobar
But the effect of a gdef
is truly global and in complicated situations with many groups can be different from a local assignment one scope 'above' the environment.
Some assignments like LaTeX counter operations are always global and don't need additional work to break out of environments, but most other assignments are local and will need something like gdef
to also apply outside of the environment.
Note that you made it easy for me by using def
(which has a global companion gdef
). LaTeX's newcommand
and renewcommand
for example do not have global companions and must be replaced with a gdef
construction.
When you define an environment with
newenvironmentenvnamebegincodeendcode
and use it with
beginenvname
body
endenvname
LaTeX roughly executes
begingroup
begincode % as envname
body
endcode % as endenvname
endgroup
That means that all assignments that happen within begincode
, endcode
and bodycode
are local to the group implicit in the environment.
In your case the deffoobar
then applies only to the environment - outside of the environment the original value is restored. You could go all-in with gdef
and make a global assignment:
gdeffoobar
But the effect of a gdef
is truly global and in complicated situations with many groups can be different from a local assignment one scope 'above' the environment.
Some assignments like LaTeX counter operations are always global and don't need additional work to break out of environments, but most other assignments are local and will need something like gdef
to also apply outside of the environment.
Note that you made it easy for me by using def
(which has a global companion gdef
). LaTeX's newcommand
and renewcommand
for example do not have global companions and must be replaced with a gdef
construction.
edited 33 mins ago
answered 1 hour ago
moewe
77.1k797292
77.1k797292
add a comment |Â
add a comment |Â
up vote
3
down vote
There are very good reasons why LaTeX opens a group upon entering an environment and closes it at exit.
First reason.
The name of the current environment is saved in the macro @currenvir
; when an end
command occurs, LaTeX can check its argument against the meaning of @currenvir
; if they agree, good, otherwise an error is raised. Then the group can be closed and @currenvir
will regain the meaning it had when begin
was executed.
The alternative would be maintaining a stack, each begin
pushing an item to the stack and each end
popping one. But since grouping is useful for other reasons, there was no point in doing it when LaTeX was born (and computer memory scarce).
Second reason
Several environments are used for special typesetting: consider for instance center
, flushleft
, enumerate
, itemize
and so on.
Each of these environments may set a lot of parameters and here we see that maintaining a stack would become painful; just think to enumerate
nested in itemize
. Not to mention technical difficulties when par
is redefined to do something different from its usual action and maybe this redefinition contains code to redefine par
itself as soon as the modified one is executed.
Grouping ensures that the previous values of the parameters modified by the environment are automatically restored at the environment's end.
By the way, this is a reason why there are no chapter
, section
and so on environments, which might be attractive at first thought: a very long chapter
environment, with many inner environments, could fill the stack memory TeX allocates for restoring values. Again, consider when LaTeX was written, with severe computer memory constraints.
Disadvantages
Look at the code for lrbox
to see how the problem of setting a box in an environment, but its value preserved at endlrbox
is overcome. Interesting code to study, particularly at hboxbegingroupaftergroup
that may surprise at first reading ;-)
It is not possible to define a macro inside an environment so that its value is propagated at the upper level without doing special tricks like the one mentioned; propagating it to two levels above is doubly tricky and so on.
Solution
Use a global definition: gdeffoobar
will propagate the redefinition to all levels. See globalrenewcommand equivalent of globaldef if you want to use LaTeX-like syntax instead, with the usual protections.
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
add a comment |Â
up vote
3
down vote
There are very good reasons why LaTeX opens a group upon entering an environment and closes it at exit.
First reason.
The name of the current environment is saved in the macro @currenvir
; when an end
command occurs, LaTeX can check its argument against the meaning of @currenvir
; if they agree, good, otherwise an error is raised. Then the group can be closed and @currenvir
will regain the meaning it had when begin
was executed.
The alternative would be maintaining a stack, each begin
pushing an item to the stack and each end
popping one. But since grouping is useful for other reasons, there was no point in doing it when LaTeX was born (and computer memory scarce).
Second reason
Several environments are used for special typesetting: consider for instance center
, flushleft
, enumerate
, itemize
and so on.
Each of these environments may set a lot of parameters and here we see that maintaining a stack would become painful; just think to enumerate
nested in itemize
. Not to mention technical difficulties when par
is redefined to do something different from its usual action and maybe this redefinition contains code to redefine par
itself as soon as the modified one is executed.
Grouping ensures that the previous values of the parameters modified by the environment are automatically restored at the environment's end.
By the way, this is a reason why there are no chapter
, section
and so on environments, which might be attractive at first thought: a very long chapter
environment, with many inner environments, could fill the stack memory TeX allocates for restoring values. Again, consider when LaTeX was written, with severe computer memory constraints.
Disadvantages
Look at the code for lrbox
to see how the problem of setting a box in an environment, but its value preserved at endlrbox
is overcome. Interesting code to study, particularly at hboxbegingroupaftergroup
that may surprise at first reading ;-)
It is not possible to define a macro inside an environment so that its value is propagated at the upper level without doing special tricks like the one mentioned; propagating it to two levels above is doubly tricky and so on.
Solution
Use a global definition: gdeffoobar
will propagate the redefinition to all levels. See globalrenewcommand equivalent of globaldef if you want to use LaTeX-like syntax instead, with the usual protections.
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
add a comment |Â
up vote
3
down vote
up vote
3
down vote
There are very good reasons why LaTeX opens a group upon entering an environment and closes it at exit.
First reason.
The name of the current environment is saved in the macro @currenvir
; when an end
command occurs, LaTeX can check its argument against the meaning of @currenvir
; if they agree, good, otherwise an error is raised. Then the group can be closed and @currenvir
will regain the meaning it had when begin
was executed.
The alternative would be maintaining a stack, each begin
pushing an item to the stack and each end
popping one. But since grouping is useful for other reasons, there was no point in doing it when LaTeX was born (and computer memory scarce).
Second reason
Several environments are used for special typesetting: consider for instance center
, flushleft
, enumerate
, itemize
and so on.
Each of these environments may set a lot of parameters and here we see that maintaining a stack would become painful; just think to enumerate
nested in itemize
. Not to mention technical difficulties when par
is redefined to do something different from its usual action and maybe this redefinition contains code to redefine par
itself as soon as the modified one is executed.
Grouping ensures that the previous values of the parameters modified by the environment are automatically restored at the environment's end.
By the way, this is a reason why there are no chapter
, section
and so on environments, which might be attractive at first thought: a very long chapter
environment, with many inner environments, could fill the stack memory TeX allocates for restoring values. Again, consider when LaTeX was written, with severe computer memory constraints.
Disadvantages
Look at the code for lrbox
to see how the problem of setting a box in an environment, but its value preserved at endlrbox
is overcome. Interesting code to study, particularly at hboxbegingroupaftergroup
that may surprise at first reading ;-)
It is not possible to define a macro inside an environment so that its value is propagated at the upper level without doing special tricks like the one mentioned; propagating it to two levels above is doubly tricky and so on.
Solution
Use a global definition: gdeffoobar
will propagate the redefinition to all levels. See globalrenewcommand equivalent of globaldef if you want to use LaTeX-like syntax instead, with the usual protections.
There are very good reasons why LaTeX opens a group upon entering an environment and closes it at exit.
First reason.
The name of the current environment is saved in the macro @currenvir
; when an end
command occurs, LaTeX can check its argument against the meaning of @currenvir
; if they agree, good, otherwise an error is raised. Then the group can be closed and @currenvir
will regain the meaning it had when begin
was executed.
The alternative would be maintaining a stack, each begin
pushing an item to the stack and each end
popping one. But since grouping is useful for other reasons, there was no point in doing it when LaTeX was born (and computer memory scarce).
Second reason
Several environments are used for special typesetting: consider for instance center
, flushleft
, enumerate
, itemize
and so on.
Each of these environments may set a lot of parameters and here we see that maintaining a stack would become painful; just think to enumerate
nested in itemize
. Not to mention technical difficulties when par
is redefined to do something different from its usual action and maybe this redefinition contains code to redefine par
itself as soon as the modified one is executed.
Grouping ensures that the previous values of the parameters modified by the environment are automatically restored at the environment's end.
By the way, this is a reason why there are no chapter
, section
and so on environments, which might be attractive at first thought: a very long chapter
environment, with many inner environments, could fill the stack memory TeX allocates for restoring values. Again, consider when LaTeX was written, with severe computer memory constraints.
Disadvantages
Look at the code for lrbox
to see how the problem of setting a box in an environment, but its value preserved at endlrbox
is overcome. Interesting code to study, particularly at hboxbegingroupaftergroup
that may surprise at first reading ;-)
It is not possible to define a macro inside an environment so that its value is propagated at the upper level without doing special tricks like the one mentioned; propagating it to two levels above is doubly tricky and so on.
Solution
Use a global definition: gdeffoobar
will propagate the redefinition to all levels. See globalrenewcommand equivalent of globaldef if you want to use LaTeX-like syntax instead, with the usual protections.
edited 9 mins ago
moewe
77.1k797292
77.1k797292
answered 16 mins ago
egreg
685k8418273076
685k8418273076
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
add a comment |Â
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
Thanks for the in-depth explanation. I really appreciate this :-)
â cmaster
2 mins ago
add a comment |Â
cmaster is a new contributor. Be nice, and check out our Code of Conduct.
cmaster is a new contributor. Be nice, and check out our Code of Conduct.
cmaster is a new contributor. Be nice, and check out our Code of Conduct.
cmaster is a new contributor. Be nice, and check out our Code of Conduct.
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
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f452911%2fmacro-losing-value-when-exiting-custom-environment%23new-answer', 'question_page');
);
Post as a guest
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
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
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
2
begintest
implicitly starts a group andendtest
ends it. That means that all assignment that happen in your environment are local to the environment. If you usegdeffoobar
the assignment is global and will be available outside the environment as well (and indeed globally).â moewe
1 hour ago
@moewe Thanks a lot.
gdef
seems to be exactly what I need. Would you mind fleshing that out in an answer so that I may vote on it?â cmaster
1 hour ago
1
On my way......
â moewe
1 hour ago