6
$\begingroup$

I'm trying to figure out what is the best way to protect symbols within a package (a function's options in particular) so that no other value can be assigned to it.

Consider a function myFunc:

Options[myFunc, OptionsPattern[]] = {op1->5}
myFunc[x_] :=
  Module[{},
    (* Function's core implementation *)
    Print[OptionValue[op1]+2];
  ]

If I leave it as is, op1 is unprotected and anyone can assign a value to it. That doesn't seem to affect myFunc's functionality, but seems perhaps unprofessional (?).

Checking the symbol PlotRange, for instance, turns out protected, as it is an option for Plot[] and ListPlot[].

Up until now I've been protecting my options with (right before myFunc's definition):

Unprotect[op1]; 
op1 = op1;
Protect[op1];

I must've seen that somewhere, because I don't remember coming up with it. Apart from the self definition op1=op1, I understand it, but I'm curious to what the "correct" way to do it would be. And also, do I even need to protect it? Or is it just for clarity for the user (and other package makers), saying "Hey, this symbol is an option! Don't get it confused with your variables.".

EDIT: I forgot to mention. I'm also writing documentation for this application, in Wolfram Workbench. So, it's useful to have well defined protected symbols in general that I can document.

$\endgroup$
3
  • 1
    $\begingroup$ If your function myFunc and its options form a part of a package that you will publicly release, then I certainly would recommend Protecting it. If its something you will use on your own, it's up to you -- do you have a tendency to forget your option names, and assign values to them? $\endgroup$
    – QuantumDot
    Nov 8, 2017 at 23:10
  • 1
    $\begingroup$ Indeed not a at all. I do forget their name, but I don't use them as variables. I usually write them with first capital letter, like Op1 (forgot to do so in example), and I write my variables with lowercase letter, so there's very little chance for collision $\endgroup$
    – A. Vieira
    Nov 9, 2017 at 7:21
  • $\begingroup$ You put OptionsPattern[] in Options[] instead of myFunc in your example code. $\endgroup$
    – Szabolcs
    Nov 9, 2017 at 9:37

2 Answers 2

7
$\begingroup$

Protect everything from the package's context, unless it is explicitly meant to be set by the package's users*. It doesn't matter if the symbol is an option or not.

BeginPackage["Foo`"];

Unprotect["Foo`*"];

(* list all symbols meant for export,
   including any symbols used as options only *)

Begin["`Private`"];

(* package code *)

With[{syms = Names["Foo`*"]},
  SetAttributes[syms, {Protected, ReadProtected}]
];    

End[];

EndPackage[];

I agree with @Henrik that it is good practice to use strings for option names to limit name pollution (and reduce the chance of name conflicts), especially if the option will be used with a single function only.

It is true that if you use the Workbench documentation tools, then it will not be possible to have a separate documentation page for a string option. But should you have one? I prefer to document options in the doc page of the function they belong to—except when the same option is used by several functions with the very same meaning.


* Even then it's probably better to have the settable symbol protected and overload Set for it—that way you can have error checking for its value.

$\endgroup$
3
  • $\begingroup$ Thanks for this contributions.In most of my cases the option is only for that function. Indeed documenting the option in the docpage of the function is better. I don't really check the doc pages for options themselves that often, specially given the option only works for that function. $\endgroup$
    – A. Vieira
    Nov 9, 2017 at 11:04
  • $\begingroup$ BTW, I think SetAttributes[#, {Protected, ReadProtected}] & /@ Names["MArthur`*"]; can be used to protect all symbols and avoids making syms a symbol as well. $\endgroup$
    – A. Vieira
    Nov 9, 2017 at 12:59
  • $\begingroup$ @A.Vieira You're right, it should have come before the End[]. The pure function version works too, also with @ instead of /@. $\endgroup$
    – Szabolcs
    Nov 9, 2017 at 13:10
4
$\begingroup$

I always use strings as the names for the options (like "op1" instead of op1). You cannot overwrite a string. That's good! For some weird reason, you can still use the "unstringfied" version op1 as in myFunc[bla,op1->2]. Of course, myFunc[bla,"op1"->2] is also valid. So, you get safety even without Protection and still you are not forced to type many quotes.

$\endgroup$
1
  • $\begingroup$ The only thing that annoys me about string options is that I cannot use Information[] on them. Otherwise, this is a good suggestion. $\endgroup$ Nov 9, 2017 at 0:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.