Defining a command part by part












4















Let's say we have a command foo with 1 argument. Can we produce a command setfoo{aaa}{<some thing>} which redefines foo to:
if an argument of foois equal to 'aaa', do ; otherwise do what foo was supposed to do previously? I would also like to use setfoo many times, so



setfoo{a}{part1}
setfoo{b}{part2}
setfoo{c}{part3}
foo{a} foo{b} foo{c}


would produce



part1 part2 part3


I've tried the following:



documentclass{article}
usepackage{ifthen}

newcommand{foo}[1]{}
%letoldfoofoo%
newcommand{setfoo}[2]{
letoldfoofoo %<- to save current foo
renewcommand{foo}[1]{
ifthenelse{equal{##1}{#1}}{#2}{oldfoo{##1}}%
}
}
begin{document}
setfoo{a}{part1}
setfoo{b}{part2}
%setfoo{c}{part3}

foo{a} foo{a} foo{c}

end{document}


But it works only if there are <=2 uses of setfoo. Otherwise, compilation doesn't stop for a few minutes so I guess something is not working. How can this be fixed? Thanks in advance.










share|improve this question


















  • 1





    Welcome to TeX.SE!

    – Kurt
    Jan 22 at 23:58
















4















Let's say we have a command foo with 1 argument. Can we produce a command setfoo{aaa}{<some thing>} which redefines foo to:
if an argument of foois equal to 'aaa', do ; otherwise do what foo was supposed to do previously? I would also like to use setfoo many times, so



setfoo{a}{part1}
setfoo{b}{part2}
setfoo{c}{part3}
foo{a} foo{b} foo{c}


would produce



part1 part2 part3


I've tried the following:



documentclass{article}
usepackage{ifthen}

newcommand{foo}[1]{}
%letoldfoofoo%
newcommand{setfoo}[2]{
letoldfoofoo %<- to save current foo
renewcommand{foo}[1]{
ifthenelse{equal{##1}{#1}}{#2}{oldfoo{##1}}%
}
}
begin{document}
setfoo{a}{part1}
setfoo{b}{part2}
%setfoo{c}{part3}

foo{a} foo{a} foo{c}

end{document}


But it works only if there are <=2 uses of setfoo. Otherwise, compilation doesn't stop for a few minutes so I guess something is not working. How can this be fixed? Thanks in advance.










share|improve this question


















  • 1





    Welcome to TeX.SE!

    – Kurt
    Jan 22 at 23:58














4












4








4








Let's say we have a command foo with 1 argument. Can we produce a command setfoo{aaa}{<some thing>} which redefines foo to:
if an argument of foois equal to 'aaa', do ; otherwise do what foo was supposed to do previously? I would also like to use setfoo many times, so



setfoo{a}{part1}
setfoo{b}{part2}
setfoo{c}{part3}
foo{a} foo{b} foo{c}


would produce



part1 part2 part3


I've tried the following:



documentclass{article}
usepackage{ifthen}

newcommand{foo}[1]{}
%letoldfoofoo%
newcommand{setfoo}[2]{
letoldfoofoo %<- to save current foo
renewcommand{foo}[1]{
ifthenelse{equal{##1}{#1}}{#2}{oldfoo{##1}}%
}
}
begin{document}
setfoo{a}{part1}
setfoo{b}{part2}
%setfoo{c}{part3}

foo{a} foo{a} foo{c}

end{document}


But it works only if there are <=2 uses of setfoo. Otherwise, compilation doesn't stop for a few minutes so I guess something is not working. How can this be fixed? Thanks in advance.










share|improve this question














Let's say we have a command foo with 1 argument. Can we produce a command setfoo{aaa}{<some thing>} which redefines foo to:
if an argument of foois equal to 'aaa', do ; otherwise do what foo was supposed to do previously? I would also like to use setfoo many times, so



setfoo{a}{part1}
setfoo{b}{part2}
setfoo{c}{part3}
foo{a} foo{b} foo{c}


would produce



part1 part2 part3


I've tried the following:



documentclass{article}
usepackage{ifthen}

newcommand{foo}[1]{}
%letoldfoofoo%
newcommand{setfoo}[2]{
letoldfoofoo %<- to save current foo
renewcommand{foo}[1]{
ifthenelse{equal{##1}{#1}}{#2}{oldfoo{##1}}%
}
}
begin{document}
setfoo{a}{part1}
setfoo{b}{part2}
%setfoo{c}{part3}

foo{a} foo{a} foo{c}

end{document}


But it works only if there are <=2 uses of setfoo. Otherwise, compilation doesn't stop for a few minutes so I guess something is not working. How can this be fixed? Thanks in advance.







macros conditionals






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 22 at 23:42









Tomasz23Tomasz23

506




506








  • 1





    Welcome to TeX.SE!

    – Kurt
    Jan 22 at 23:58














  • 1





    Welcome to TeX.SE!

    – Kurt
    Jan 22 at 23:58








1




1





Welcome to TeX.SE!

– Kurt
Jan 22 at 23:58





Welcome to TeX.SE!

– Kurt
Jan 22 at 23:58










2 Answers
2






active

oldest

votes


















4














This is a job for csname:



newcommand{setfoo}[2]{%
expandafternewcommandcsname tomasz@#1endcsname{#2}%
}
newcommand{foo}[1]{csname tomasz@#1endcsname}


You might use a check in foo that the command is actually defined:



makeatletter
newcommand{foo}[1]{%
ifcsname tomasz@#1endcsname
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
{csname tomasz@#1endcsname}%
{BUMMER!}%
}
makeatother





share|improve this answer































    1














    In your special case, where foo is always to process a single undelimited non-optional argument, you can probably apply some expansion trickery for "flushing" the tokens that form the current definition of foo into the new definition of foo—one of the expansion-tricks is (ab)using romannumeral for triggering expansion until LaTeX has found the number 0. romannumeral's underlying conversion-routine does "swallow" non-positive numbers while silently not delivering any token at all:



    documentclass{article}
    usepackage{ifthen}

    newcommandPassFirstToSecond[2]{#2{#1}}%

    newcommand{foo}[1]{There is no setting for value #1.}

    newcommand{setfoo}[2]{%
    expandafterPassFirstToSecond
    expandafter{%
    romannumeralexpandafterPassFirstToSecondexpandafter{foo{##1}}%
    {0 ifthenelse{equal{##1}{#1}}{#2}}%
    }{renewcommand{foo}[1]}%
    }

    parindent=0ex
    parskip=bigskipamount

    begin{document}

    texttt{stringfoospace currently is defined as:\ meaningfoo}

    setfoo{a}{part1}
    texttt{stringfoospace currently is defined as:\ meaningfoo}

    setfoo{b}{part2}
    texttt{stringfoospace currently is defined as:\ meaningfoo}

    setfoo{c}{part3}
    texttt{stringfoospace currently is defined as:\ meaningfoo}

    hrulefill

    Some testing:

    verb|foo{a}| yields: foo{a}

    verb|foo{b}| yields: foo{b}

    verb|foo{c}| yields: foo{c}

    verb|foo{y}| yields: foo{y}

    end{document}


    enter image description here






    share|improve this answer

























      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
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f471399%2fdefining-a-command-part-by-part%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









      4














      This is a job for csname:



      newcommand{setfoo}[2]{%
      expandafternewcommandcsname tomasz@#1endcsname{#2}%
      }
      newcommand{foo}[1]{csname tomasz@#1endcsname}


      You might use a check in foo that the command is actually defined:



      makeatletter
      newcommand{foo}[1]{%
      ifcsname tomasz@#1endcsname
      expandafter@firstoftwo
      else
      expandafter@secondoftwo
      fi
      {csname tomasz@#1endcsname}%
      {BUMMER!}%
      }
      makeatother





      share|improve this answer




























        4














        This is a job for csname:



        newcommand{setfoo}[2]{%
        expandafternewcommandcsname tomasz@#1endcsname{#2}%
        }
        newcommand{foo}[1]{csname tomasz@#1endcsname}


        You might use a check in foo that the command is actually defined:



        makeatletter
        newcommand{foo}[1]{%
        ifcsname tomasz@#1endcsname
        expandafter@firstoftwo
        else
        expandafter@secondoftwo
        fi
        {csname tomasz@#1endcsname}%
        {BUMMER!}%
        }
        makeatother





        share|improve this answer


























          4












          4








          4







          This is a job for csname:



          newcommand{setfoo}[2]{%
          expandafternewcommandcsname tomasz@#1endcsname{#2}%
          }
          newcommand{foo}[1]{csname tomasz@#1endcsname}


          You might use a check in foo that the command is actually defined:



          makeatletter
          newcommand{foo}[1]{%
          ifcsname tomasz@#1endcsname
          expandafter@firstoftwo
          else
          expandafter@secondoftwo
          fi
          {csname tomasz@#1endcsname}%
          {BUMMER!}%
          }
          makeatother





          share|improve this answer













          This is a job for csname:



          newcommand{setfoo}[2]{%
          expandafternewcommandcsname tomasz@#1endcsname{#2}%
          }
          newcommand{foo}[1]{csname tomasz@#1endcsname}


          You might use a check in foo that the command is actually defined:



          makeatletter
          newcommand{foo}[1]{%
          ifcsname tomasz@#1endcsname
          expandafter@firstoftwo
          else
          expandafter@secondoftwo
          fi
          {csname tomasz@#1endcsname}%
          {BUMMER!}%
          }
          makeatother






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 22 at 23:49









          egregegreg

          716k8619033189




          716k8619033189























              1














              In your special case, where foo is always to process a single undelimited non-optional argument, you can probably apply some expansion trickery for "flushing" the tokens that form the current definition of foo into the new definition of foo—one of the expansion-tricks is (ab)using romannumeral for triggering expansion until LaTeX has found the number 0. romannumeral's underlying conversion-routine does "swallow" non-positive numbers while silently not delivering any token at all:



              documentclass{article}
              usepackage{ifthen}

              newcommandPassFirstToSecond[2]{#2{#1}}%

              newcommand{foo}[1]{There is no setting for value #1.}

              newcommand{setfoo}[2]{%
              expandafterPassFirstToSecond
              expandafter{%
              romannumeralexpandafterPassFirstToSecondexpandafter{foo{##1}}%
              {0 ifthenelse{equal{##1}{#1}}{#2}}%
              }{renewcommand{foo}[1]}%
              }

              parindent=0ex
              parskip=bigskipamount

              begin{document}

              texttt{stringfoospace currently is defined as:\ meaningfoo}

              setfoo{a}{part1}
              texttt{stringfoospace currently is defined as:\ meaningfoo}

              setfoo{b}{part2}
              texttt{stringfoospace currently is defined as:\ meaningfoo}

              setfoo{c}{part3}
              texttt{stringfoospace currently is defined as:\ meaningfoo}

              hrulefill

              Some testing:

              verb|foo{a}| yields: foo{a}

              verb|foo{b}| yields: foo{b}

              verb|foo{c}| yields: foo{c}

              verb|foo{y}| yields: foo{y}

              end{document}


              enter image description here






              share|improve this answer






























                1














                In your special case, where foo is always to process a single undelimited non-optional argument, you can probably apply some expansion trickery for "flushing" the tokens that form the current definition of foo into the new definition of foo—one of the expansion-tricks is (ab)using romannumeral for triggering expansion until LaTeX has found the number 0. romannumeral's underlying conversion-routine does "swallow" non-positive numbers while silently not delivering any token at all:



                documentclass{article}
                usepackage{ifthen}

                newcommandPassFirstToSecond[2]{#2{#1}}%

                newcommand{foo}[1]{There is no setting for value #1.}

                newcommand{setfoo}[2]{%
                expandafterPassFirstToSecond
                expandafter{%
                romannumeralexpandafterPassFirstToSecondexpandafter{foo{##1}}%
                {0 ifthenelse{equal{##1}{#1}}{#2}}%
                }{renewcommand{foo}[1]}%
                }

                parindent=0ex
                parskip=bigskipamount

                begin{document}

                texttt{stringfoospace currently is defined as:\ meaningfoo}

                setfoo{a}{part1}
                texttt{stringfoospace currently is defined as:\ meaningfoo}

                setfoo{b}{part2}
                texttt{stringfoospace currently is defined as:\ meaningfoo}

                setfoo{c}{part3}
                texttt{stringfoospace currently is defined as:\ meaningfoo}

                hrulefill

                Some testing:

                verb|foo{a}| yields: foo{a}

                verb|foo{b}| yields: foo{b}

                verb|foo{c}| yields: foo{c}

                verb|foo{y}| yields: foo{y}

                end{document}


                enter image description here






                share|improve this answer




























                  1












                  1








                  1







                  In your special case, where foo is always to process a single undelimited non-optional argument, you can probably apply some expansion trickery for "flushing" the tokens that form the current definition of foo into the new definition of foo—one of the expansion-tricks is (ab)using romannumeral for triggering expansion until LaTeX has found the number 0. romannumeral's underlying conversion-routine does "swallow" non-positive numbers while silently not delivering any token at all:



                  documentclass{article}
                  usepackage{ifthen}

                  newcommandPassFirstToSecond[2]{#2{#1}}%

                  newcommand{foo}[1]{There is no setting for value #1.}

                  newcommand{setfoo}[2]{%
                  expandafterPassFirstToSecond
                  expandafter{%
                  romannumeralexpandafterPassFirstToSecondexpandafter{foo{##1}}%
                  {0 ifthenelse{equal{##1}{#1}}{#2}}%
                  }{renewcommand{foo}[1]}%
                  }

                  parindent=0ex
                  parskip=bigskipamount

                  begin{document}

                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  setfoo{a}{part1}
                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  setfoo{b}{part2}
                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  setfoo{c}{part3}
                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  hrulefill

                  Some testing:

                  verb|foo{a}| yields: foo{a}

                  verb|foo{b}| yields: foo{b}

                  verb|foo{c}| yields: foo{c}

                  verb|foo{y}| yields: foo{y}

                  end{document}


                  enter image description here






                  share|improve this answer















                  In your special case, where foo is always to process a single undelimited non-optional argument, you can probably apply some expansion trickery for "flushing" the tokens that form the current definition of foo into the new definition of foo—one of the expansion-tricks is (ab)using romannumeral for triggering expansion until LaTeX has found the number 0. romannumeral's underlying conversion-routine does "swallow" non-positive numbers while silently not delivering any token at all:



                  documentclass{article}
                  usepackage{ifthen}

                  newcommandPassFirstToSecond[2]{#2{#1}}%

                  newcommand{foo}[1]{There is no setting for value #1.}

                  newcommand{setfoo}[2]{%
                  expandafterPassFirstToSecond
                  expandafter{%
                  romannumeralexpandafterPassFirstToSecondexpandafter{foo{##1}}%
                  {0 ifthenelse{equal{##1}{#1}}{#2}}%
                  }{renewcommand{foo}[1]}%
                  }

                  parindent=0ex
                  parskip=bigskipamount

                  begin{document}

                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  setfoo{a}{part1}
                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  setfoo{b}{part2}
                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  setfoo{c}{part3}
                  texttt{stringfoospace currently is defined as:\ meaningfoo}

                  hrulefill

                  Some testing:

                  verb|foo{a}| yields: foo{a}

                  verb|foo{b}| yields: foo{b}

                  verb|foo{c}| yields: foo{c}

                  verb|foo{y}| yields: foo{y}

                  end{document}


                  enter image description here







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 27 at 3:34

























                  answered Jan 27 at 3:17









                  Ulrich DiezUlrich Diez

                  4,470616




                  4,470616






























                      draft saved

                      draft discarded




















































                      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.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f471399%2fdefining-a-command-part-by-part%23new-answer', 'question_page');
                      }
                      );

                      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







                      Popular posts from this blog

                      How to change which sound is reproduced for terminal bell?

                      Can I use Tabulator js library in my java Spring + Thymeleaf project?

                      Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents