Renaming options of custom functions while preserving backwards compatibility

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











up vote
3
down vote

favorite












I have a package with many functions. There is an option name that several functions share. I feel that the current name of this option was not the best choice. I would like to rename it, but at the same time, I would like to preserve backwards compatibility.



If this option name were a symbol, the simple solution would be



oldName = newName


(And, of course, replacing all occurrences of the old name with the new one in the package.)



But in this case, the option name is a string. Even if it weren't, OptionValue does not distinguish between string and symbol names. It is preferable to handle both.



The package uses the standard option handling with OptionsPattern/OptionValue.



What is the best way to rename this option? I am looking to change as little existing code as possible (except for basic find-and-replace of names), and take as little performance hit as possible.










share|improve this question

























    up vote
    3
    down vote

    favorite












    I have a package with many functions. There is an option name that several functions share. I feel that the current name of this option was not the best choice. I would like to rename it, but at the same time, I would like to preserve backwards compatibility.



    If this option name were a symbol, the simple solution would be



    oldName = newName


    (And, of course, replacing all occurrences of the old name with the new one in the package.)



    But in this case, the option name is a string. Even if it weren't, OptionValue does not distinguish between string and symbol names. It is preferable to handle both.



    The package uses the standard option handling with OptionsPattern/OptionValue.



    What is the best way to rename this option? I am looking to change as little existing code as possible (except for basic find-and-replace of names), and take as little performance hit as possible.










    share|improve this question























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      I have a package with many functions. There is an option name that several functions share. I feel that the current name of this option was not the best choice. I would like to rename it, but at the same time, I would like to preserve backwards compatibility.



      If this option name were a symbol, the simple solution would be



      oldName = newName


      (And, of course, replacing all occurrences of the old name with the new one in the package.)



      But in this case, the option name is a string. Even if it weren't, OptionValue does not distinguish between string and symbol names. It is preferable to handle both.



      The package uses the standard option handling with OptionsPattern/OptionValue.



      What is the best way to rename this option? I am looking to change as little existing code as possible (except for basic find-and-replace of names), and take as little performance hit as possible.










      share|improve this question













      I have a package with many functions. There is an option name that several functions share. I feel that the current name of this option was not the best choice. I would like to rename it, but at the same time, I would like to preserve backwards compatibility.



      If this option name were a symbol, the simple solution would be



      oldName = newName


      (And, of course, replacing all occurrences of the old name with the new one in the package.)



      But in this case, the option name is a string. Even if it weren't, OptionValue does not distinguish between string and symbol names. It is preferable to handle both.



      The package uses the standard option handling with OptionsPattern/OptionValue.



      What is the best way to rename this option? I am looking to change as little existing code as possible (except for basic find-and-replace of names), and take as little performance hit as possible.







      options






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 1 hour ago









      Szabolcs

      155k13420911




      155k13420911




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          1
          down vote













          You can try the following:



          Attributes[HandleLegacyOption] = HoldAll;
          HandleLegacyOption[o : OptionValue[sym_, opts_, name_]] :=
          o //. Fallback[old_] :> OptionValue[sym, opts, old]


          This can be used the following way:



          Options[f] = "bar" -> Fallback["foo"], "foo" -> 1;
          f[OptionsPattern] := HandleLegacyOption@OptionValue["bar"]

          f
          f["bar" -> 2]
          f["foo" -> 2]
          f["foo" -> 2, "bar" -> 3]
          (* 1 *)
          (* 2 *)
          (* 2 *)
          (* 3 *)


          As you can see, setting either option works, and the new name takes precedence over the old one.



          How?



          Since OptionValue is a very special function, we can't do much other than explicitly leaving OptionValue[…] in the r.h.s. of our definitions. But one thing we can use is the fact that OptionValue[…] constructs are always expanded, no matter where they appear (see also linked question):



          g[OptionsPattern] := Hold@OptionValue["foo"]
          g["bar" -> 1]
          (* Hold[OptionValue[g, "bar" -> 1, "foo"]] *)


          So as long as we have OptionValue[…] explicitly appearing, we have access to:



          • The symbol, and thus the defaults

          • The explicitly specified options

          • The queried options

          The function HandleLegacyOption above uses this information by repeatedly querying option values as long as the result is Fallback[oldName]. This essentially defaults the new option to the value of another option.



          Possible extensions



          As mentioned earlier, we need OptionValue to appear on the r.h.s. of the definition, otherwise we won't get the automatic expansion of all the information we need. One possible way to (partially) automate this wrapping of OptionValue might be:



          HoldPattern[lhs_ // AddLegacyOptionHandling := rhs_] ^:=
          Hold[rhs] /.
          o_OptionValue :> HandleLegacyOption@o /.
          Hold[proc_] :> (lhs := proc)


          This automatically wraps all OptionValue expressions on the r.h.s. in HandleLegacyOption, e.g.



          f[OptionsPattern] // AddLegacyOptionHandling := OptionValue["bar"]


          yields the same result as in the first example.






          share|improve this answer



























            up vote
            1
            down vote













            This is my new approach. It is minimal invasive in the sense that it has to redefine OptionValue to handle only the new option "newopt" differently:



            optionAliases = <|"newopt" -> "oldopt"|>;
            Unprotect[OptionValue];
            OptionValue[f_, opts_, "newopt"] := If[
            ("newopt" /. opts) =!= "newopt",
            First[OptionValue[f, opts, "newopt"]],
            First[OptionValue[f, opts, optionAliases["newopt"]]] /.
            Automatic :> First[OptionValue[f, opts, "newopt"]]
            ];
            Protect[OptionValue];


            Now declare a function f in the classical way, but set the defaults for all "old" options to Automatic (or to another custom symbol):



            ClearAll[f];
            Options[f] =
            "newopt" -> 1,
            "oldopt" -> Automatic
            ;
            f[opts : OptionsPattern] := OptionValue["newopt"]


            Let's see what happens:



            f
            f["newopt" -> 2]
            f["oldopt" -> 3]
            f["newopt" -> 4, "oldopt" -> 3]



            1



            2



            3



            4




            Note that we rely on the fact that OptionValue will treat OptionValue[f, opts, "newopt"] as before. So this will only work if you call OptionValue["newopt"], not if you request it with several option values at once like in OptionValue["opt1", "opt2", ... "newopt", ... ]. One might be able to make it work by specifying an additional rule à la



            OptionValue[
            f_,
            opts_,
            list_List?(x [Function] Length[list] >= 2 && MemberQ[list, "newopt"])
            ] := ...


            But I am afraid that this will slow down the overall system.



            Of course, you can also specify special behavior only for selected functions with



            Unprotect[OptionValue];
            OptionValue[f, opts_, "newopt"] := ...
            OptionValue[h, opts_, "newopt"] := ...
            Protect[OptionValue];


            making this somewhat more robust. I also tried TagSet



            f /: OptionValue[f, opts_, "newopt"] := ...


            but this wouldn't work as OptionValue still branches to its conventional definition this way.






            share|improve this answer






















              Your Answer





              StackExchange.ifUsing("editor", function ()
              return StackExchange.using("mathjaxEditing", function ()
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
              );
              );
              , "mathjax-editing");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "387"
              ;
              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: 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%2fmathematica.stackexchange.com%2fquestions%2f185264%2frenaming-options-of-custom-functions-while-preserving-backwards-compatibility%23new-answer', 'question_page');

              );

              Post as a guest






























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              1
              down vote













              You can try the following:



              Attributes[HandleLegacyOption] = HoldAll;
              HandleLegacyOption[o : OptionValue[sym_, opts_, name_]] :=
              o //. Fallback[old_] :> OptionValue[sym, opts, old]


              This can be used the following way:



              Options[f] = "bar" -> Fallback["foo"], "foo" -> 1;
              f[OptionsPattern] := HandleLegacyOption@OptionValue["bar"]

              f
              f["bar" -> 2]
              f["foo" -> 2]
              f["foo" -> 2, "bar" -> 3]
              (* 1 *)
              (* 2 *)
              (* 2 *)
              (* 3 *)


              As you can see, setting either option works, and the new name takes precedence over the old one.



              How?



              Since OptionValue is a very special function, we can't do much other than explicitly leaving OptionValue[…] in the r.h.s. of our definitions. But one thing we can use is the fact that OptionValue[…] constructs are always expanded, no matter where they appear (see also linked question):



              g[OptionsPattern] := Hold@OptionValue["foo"]
              g["bar" -> 1]
              (* Hold[OptionValue[g, "bar" -> 1, "foo"]] *)


              So as long as we have OptionValue[…] explicitly appearing, we have access to:



              • The symbol, and thus the defaults

              • The explicitly specified options

              • The queried options

              The function HandleLegacyOption above uses this information by repeatedly querying option values as long as the result is Fallback[oldName]. This essentially defaults the new option to the value of another option.



              Possible extensions



              As mentioned earlier, we need OptionValue to appear on the r.h.s. of the definition, otherwise we won't get the automatic expansion of all the information we need. One possible way to (partially) automate this wrapping of OptionValue might be:



              HoldPattern[lhs_ // AddLegacyOptionHandling := rhs_] ^:=
              Hold[rhs] /.
              o_OptionValue :> HandleLegacyOption@o /.
              Hold[proc_] :> (lhs := proc)


              This automatically wraps all OptionValue expressions on the r.h.s. in HandleLegacyOption, e.g.



              f[OptionsPattern] // AddLegacyOptionHandling := OptionValue["bar"]


              yields the same result as in the first example.






              share|improve this answer
























                up vote
                1
                down vote













                You can try the following:



                Attributes[HandleLegacyOption] = HoldAll;
                HandleLegacyOption[o : OptionValue[sym_, opts_, name_]] :=
                o //. Fallback[old_] :> OptionValue[sym, opts, old]


                This can be used the following way:



                Options[f] = "bar" -> Fallback["foo"], "foo" -> 1;
                f[OptionsPattern] := HandleLegacyOption@OptionValue["bar"]

                f
                f["bar" -> 2]
                f["foo" -> 2]
                f["foo" -> 2, "bar" -> 3]
                (* 1 *)
                (* 2 *)
                (* 2 *)
                (* 3 *)


                As you can see, setting either option works, and the new name takes precedence over the old one.



                How?



                Since OptionValue is a very special function, we can't do much other than explicitly leaving OptionValue[…] in the r.h.s. of our definitions. But one thing we can use is the fact that OptionValue[…] constructs are always expanded, no matter where they appear (see also linked question):



                g[OptionsPattern] := Hold@OptionValue["foo"]
                g["bar" -> 1]
                (* Hold[OptionValue[g, "bar" -> 1, "foo"]] *)


                So as long as we have OptionValue[…] explicitly appearing, we have access to:



                • The symbol, and thus the defaults

                • The explicitly specified options

                • The queried options

                The function HandleLegacyOption above uses this information by repeatedly querying option values as long as the result is Fallback[oldName]. This essentially defaults the new option to the value of another option.



                Possible extensions



                As mentioned earlier, we need OptionValue to appear on the r.h.s. of the definition, otherwise we won't get the automatic expansion of all the information we need. One possible way to (partially) automate this wrapping of OptionValue might be:



                HoldPattern[lhs_ // AddLegacyOptionHandling := rhs_] ^:=
                Hold[rhs] /.
                o_OptionValue :> HandleLegacyOption@o /.
                Hold[proc_] :> (lhs := proc)


                This automatically wraps all OptionValue expressions on the r.h.s. in HandleLegacyOption, e.g.



                f[OptionsPattern] // AddLegacyOptionHandling := OptionValue["bar"]


                yields the same result as in the first example.






                share|improve this answer






















                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  You can try the following:



                  Attributes[HandleLegacyOption] = HoldAll;
                  HandleLegacyOption[o : OptionValue[sym_, opts_, name_]] :=
                  o //. Fallback[old_] :> OptionValue[sym, opts, old]


                  This can be used the following way:



                  Options[f] = "bar" -> Fallback["foo"], "foo" -> 1;
                  f[OptionsPattern] := HandleLegacyOption@OptionValue["bar"]

                  f
                  f["bar" -> 2]
                  f["foo" -> 2]
                  f["foo" -> 2, "bar" -> 3]
                  (* 1 *)
                  (* 2 *)
                  (* 2 *)
                  (* 3 *)


                  As you can see, setting either option works, and the new name takes precedence over the old one.



                  How?



                  Since OptionValue is a very special function, we can't do much other than explicitly leaving OptionValue[…] in the r.h.s. of our definitions. But one thing we can use is the fact that OptionValue[…] constructs are always expanded, no matter where they appear (see also linked question):



                  g[OptionsPattern] := Hold@OptionValue["foo"]
                  g["bar" -> 1]
                  (* Hold[OptionValue[g, "bar" -> 1, "foo"]] *)


                  So as long as we have OptionValue[…] explicitly appearing, we have access to:



                  • The symbol, and thus the defaults

                  • The explicitly specified options

                  • The queried options

                  The function HandleLegacyOption above uses this information by repeatedly querying option values as long as the result is Fallback[oldName]. This essentially defaults the new option to the value of another option.



                  Possible extensions



                  As mentioned earlier, we need OptionValue to appear on the r.h.s. of the definition, otherwise we won't get the automatic expansion of all the information we need. One possible way to (partially) automate this wrapping of OptionValue might be:



                  HoldPattern[lhs_ // AddLegacyOptionHandling := rhs_] ^:=
                  Hold[rhs] /.
                  o_OptionValue :> HandleLegacyOption@o /.
                  Hold[proc_] :> (lhs := proc)


                  This automatically wraps all OptionValue expressions on the r.h.s. in HandleLegacyOption, e.g.



                  f[OptionsPattern] // AddLegacyOptionHandling := OptionValue["bar"]


                  yields the same result as in the first example.






                  share|improve this answer












                  You can try the following:



                  Attributes[HandleLegacyOption] = HoldAll;
                  HandleLegacyOption[o : OptionValue[sym_, opts_, name_]] :=
                  o //. Fallback[old_] :> OptionValue[sym, opts, old]


                  This can be used the following way:



                  Options[f] = "bar" -> Fallback["foo"], "foo" -> 1;
                  f[OptionsPattern] := HandleLegacyOption@OptionValue["bar"]

                  f
                  f["bar" -> 2]
                  f["foo" -> 2]
                  f["foo" -> 2, "bar" -> 3]
                  (* 1 *)
                  (* 2 *)
                  (* 2 *)
                  (* 3 *)


                  As you can see, setting either option works, and the new name takes precedence over the old one.



                  How?



                  Since OptionValue is a very special function, we can't do much other than explicitly leaving OptionValue[…] in the r.h.s. of our definitions. But one thing we can use is the fact that OptionValue[…] constructs are always expanded, no matter where they appear (see also linked question):



                  g[OptionsPattern] := Hold@OptionValue["foo"]
                  g["bar" -> 1]
                  (* Hold[OptionValue[g, "bar" -> 1, "foo"]] *)


                  So as long as we have OptionValue[…] explicitly appearing, we have access to:



                  • The symbol, and thus the defaults

                  • The explicitly specified options

                  • The queried options

                  The function HandleLegacyOption above uses this information by repeatedly querying option values as long as the result is Fallback[oldName]. This essentially defaults the new option to the value of another option.



                  Possible extensions



                  As mentioned earlier, we need OptionValue to appear on the r.h.s. of the definition, otherwise we won't get the automatic expansion of all the information we need. One possible way to (partially) automate this wrapping of OptionValue might be:



                  HoldPattern[lhs_ // AddLegacyOptionHandling := rhs_] ^:=
                  Hold[rhs] /.
                  o_OptionValue :> HandleLegacyOption@o /.
                  Hold[proc_] :> (lhs := proc)


                  This automatically wraps all OptionValue expressions on the r.h.s. in HandleLegacyOption, e.g.



                  f[OptionsPattern] // AddLegacyOptionHandling := OptionValue["bar"]


                  yields the same result as in the first example.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 56 mins ago









                  Lukas Lang

                  5,3081525




                  5,3081525




















                      up vote
                      1
                      down vote













                      This is my new approach. It is minimal invasive in the sense that it has to redefine OptionValue to handle only the new option "newopt" differently:



                      optionAliases = <|"newopt" -> "oldopt"|>;
                      Unprotect[OptionValue];
                      OptionValue[f_, opts_, "newopt"] := If[
                      ("newopt" /. opts) =!= "newopt",
                      First[OptionValue[f, opts, "newopt"]],
                      First[OptionValue[f, opts, optionAliases["newopt"]]] /.
                      Automatic :> First[OptionValue[f, opts, "newopt"]]
                      ];
                      Protect[OptionValue];


                      Now declare a function f in the classical way, but set the defaults for all "old" options to Automatic (or to another custom symbol):



                      ClearAll[f];
                      Options[f] =
                      "newopt" -> 1,
                      "oldopt" -> Automatic
                      ;
                      f[opts : OptionsPattern] := OptionValue["newopt"]


                      Let's see what happens:



                      f
                      f["newopt" -> 2]
                      f["oldopt" -> 3]
                      f["newopt" -> 4, "oldopt" -> 3]



                      1



                      2



                      3



                      4




                      Note that we rely on the fact that OptionValue will treat OptionValue[f, opts, "newopt"] as before. So this will only work if you call OptionValue["newopt"], not if you request it with several option values at once like in OptionValue["opt1", "opt2", ... "newopt", ... ]. One might be able to make it work by specifying an additional rule à la



                      OptionValue[
                      f_,
                      opts_,
                      list_List?(x [Function] Length[list] >= 2 && MemberQ[list, "newopt"])
                      ] := ...


                      But I am afraid that this will slow down the overall system.



                      Of course, you can also specify special behavior only for selected functions with



                      Unprotect[OptionValue];
                      OptionValue[f, opts_, "newopt"] := ...
                      OptionValue[h, opts_, "newopt"] := ...
                      Protect[OptionValue];


                      making this somewhat more robust. I also tried TagSet



                      f /: OptionValue[f, opts_, "newopt"] := ...


                      but this wouldn't work as OptionValue still branches to its conventional definition this way.






                      share|improve this answer


























                        up vote
                        1
                        down vote













                        This is my new approach. It is minimal invasive in the sense that it has to redefine OptionValue to handle only the new option "newopt" differently:



                        optionAliases = <|"newopt" -> "oldopt"|>;
                        Unprotect[OptionValue];
                        OptionValue[f_, opts_, "newopt"] := If[
                        ("newopt" /. opts) =!= "newopt",
                        First[OptionValue[f, opts, "newopt"]],
                        First[OptionValue[f, opts, optionAliases["newopt"]]] /.
                        Automatic :> First[OptionValue[f, opts, "newopt"]]
                        ];
                        Protect[OptionValue];


                        Now declare a function f in the classical way, but set the defaults for all "old" options to Automatic (or to another custom symbol):



                        ClearAll[f];
                        Options[f] =
                        "newopt" -> 1,
                        "oldopt" -> Automatic
                        ;
                        f[opts : OptionsPattern] := OptionValue["newopt"]


                        Let's see what happens:



                        f
                        f["newopt" -> 2]
                        f["oldopt" -> 3]
                        f["newopt" -> 4, "oldopt" -> 3]



                        1



                        2



                        3



                        4




                        Note that we rely on the fact that OptionValue will treat OptionValue[f, opts, "newopt"] as before. So this will only work if you call OptionValue["newopt"], not if you request it with several option values at once like in OptionValue["opt1", "opt2", ... "newopt", ... ]. One might be able to make it work by specifying an additional rule à la



                        OptionValue[
                        f_,
                        opts_,
                        list_List?(x [Function] Length[list] >= 2 && MemberQ[list, "newopt"])
                        ] := ...


                        But I am afraid that this will slow down the overall system.



                        Of course, you can also specify special behavior only for selected functions with



                        Unprotect[OptionValue];
                        OptionValue[f, opts_, "newopt"] := ...
                        OptionValue[h, opts_, "newopt"] := ...
                        Protect[OptionValue];


                        making this somewhat more robust. I also tried TagSet



                        f /: OptionValue[f, opts_, "newopt"] := ...


                        but this wouldn't work as OptionValue still branches to its conventional definition this way.






                        share|improve this answer
























                          up vote
                          1
                          down vote










                          up vote
                          1
                          down vote









                          This is my new approach. It is minimal invasive in the sense that it has to redefine OptionValue to handle only the new option "newopt" differently:



                          optionAliases = <|"newopt" -> "oldopt"|>;
                          Unprotect[OptionValue];
                          OptionValue[f_, opts_, "newopt"] := If[
                          ("newopt" /. opts) =!= "newopt",
                          First[OptionValue[f, opts, "newopt"]],
                          First[OptionValue[f, opts, optionAliases["newopt"]]] /.
                          Automatic :> First[OptionValue[f, opts, "newopt"]]
                          ];
                          Protect[OptionValue];


                          Now declare a function f in the classical way, but set the defaults for all "old" options to Automatic (or to another custom symbol):



                          ClearAll[f];
                          Options[f] =
                          "newopt" -> 1,
                          "oldopt" -> Automatic
                          ;
                          f[opts : OptionsPattern] := OptionValue["newopt"]


                          Let's see what happens:



                          f
                          f["newopt" -> 2]
                          f["oldopt" -> 3]
                          f["newopt" -> 4, "oldopt" -> 3]



                          1



                          2



                          3



                          4




                          Note that we rely on the fact that OptionValue will treat OptionValue[f, opts, "newopt"] as before. So this will only work if you call OptionValue["newopt"], not if you request it with several option values at once like in OptionValue["opt1", "opt2", ... "newopt", ... ]. One might be able to make it work by specifying an additional rule à la



                          OptionValue[
                          f_,
                          opts_,
                          list_List?(x [Function] Length[list] >= 2 && MemberQ[list, "newopt"])
                          ] := ...


                          But I am afraid that this will slow down the overall system.



                          Of course, you can also specify special behavior only for selected functions with



                          Unprotect[OptionValue];
                          OptionValue[f, opts_, "newopt"] := ...
                          OptionValue[h, opts_, "newopt"] := ...
                          Protect[OptionValue];


                          making this somewhat more robust. I also tried TagSet



                          f /: OptionValue[f, opts_, "newopt"] := ...


                          but this wouldn't work as OptionValue still branches to its conventional definition this way.






                          share|improve this answer














                          This is my new approach. It is minimal invasive in the sense that it has to redefine OptionValue to handle only the new option "newopt" differently:



                          optionAliases = <|"newopt" -> "oldopt"|>;
                          Unprotect[OptionValue];
                          OptionValue[f_, opts_, "newopt"] := If[
                          ("newopt" /. opts) =!= "newopt",
                          First[OptionValue[f, opts, "newopt"]],
                          First[OptionValue[f, opts, optionAliases["newopt"]]] /.
                          Automatic :> First[OptionValue[f, opts, "newopt"]]
                          ];
                          Protect[OptionValue];


                          Now declare a function f in the classical way, but set the defaults for all "old" options to Automatic (or to another custom symbol):



                          ClearAll[f];
                          Options[f] =
                          "newopt" -> 1,
                          "oldopt" -> Automatic
                          ;
                          f[opts : OptionsPattern] := OptionValue["newopt"]


                          Let's see what happens:



                          f
                          f["newopt" -> 2]
                          f["oldopt" -> 3]
                          f["newopt" -> 4, "oldopt" -> 3]



                          1



                          2



                          3



                          4




                          Note that we rely on the fact that OptionValue will treat OptionValue[f, opts, "newopt"] as before. So this will only work if you call OptionValue["newopt"], not if you request it with several option values at once like in OptionValue["opt1", "opt2", ... "newopt", ... ]. One might be able to make it work by specifying an additional rule à la



                          OptionValue[
                          f_,
                          opts_,
                          list_List?(x [Function] Length[list] >= 2 && MemberQ[list, "newopt"])
                          ] := ...


                          But I am afraid that this will slow down the overall system.



                          Of course, you can also specify special behavior only for selected functions with



                          Unprotect[OptionValue];
                          OptionValue[f, opts_, "newopt"] := ...
                          OptionValue[h, opts_, "newopt"] := ...
                          Protect[OptionValue];


                          making this somewhat more robust. I also tried TagSet



                          f /: OptionValue[f, opts_, "newopt"] := ...


                          but this wouldn't work as OptionValue still branches to its conventional definition this way.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited 5 mins ago

























                          answered 38 mins ago









                          Henrik Schumacher

                          43.8k263129




                          43.8k263129



























                               

                              draft saved


                              draft discarded















































                               


                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f185264%2frenaming-options-of-custom-functions-while-preserving-backwards-compatibility%23new-answer', 'question_page');

                              );

                              Post as a guest













































































                              Comments

                              Popular posts from this blog

                              What does second last employer means? [closed]

                              List of Gilmore Girls characters

                              Confectionery