Pass by reference can be faked by using HoldAll or something similar in the definition of a "Function". But can pass by reference be faked for symbols passed as named arguments (Options)?

Let me demonstrate:

This works (when you click on the checkboxes the list changes):

Attributes[PassByArg] = {HoldFirst};
PassByArg[list_] := CheckboxBar[Dynamic[list], Range@Length@list];
aList = {1, 2, 3, 4, 5};

How can I pass the reference to list as an option?

Here is one of my failed attempts (it returns et::setraw: Cannot assign to raw object {1,2,3,4,5} when a checkbox is clicked.

Options@PassByOption = {"List" -> None};
PassByOption[opts : OptionsPattern[]] := 
  With[{i = ReleaseHold@OptionValue@"List"}, 
   CheckboxBar[Dynamic[i], Range@Length@i]];
aList = {1, 2, 3, 4, 5};
PassByOption["List" -> Hold@aList]

I always evaluate either too much (to {1,2,3,4,5}) or too little...

Perhaps some motivation is in order: I'm developing a GUI using Dynamic. Now I would like to control a list of displayed functions in some plot. If I implement this as a reference passed with a named argument I practically don't have to change any other code:)


3 Answers 3


This is a case for injector pattern:

PassByOption[opts : OptionsPattern[]] :=
  OptionValue["List"] /. Hold[l_] :> CheckboxBar[Dynamic[l], Range@Length@l]

You can check that this works with this change.

As an alternative, you can by-pass the use of Hold and clever tricks like the above, by using the longer form of OptionValue:

Options@PassByOptionAlt = {"List" -> None};
PassByOptionAlt[opts : OptionsPattern[]] :=
     Function[l, CheckboxBar[Dynamic[l], Range@Length@l], HoldAll]

This will work too, but, as mentioned by Szabolcs in comments, you will need to use RuleDelayed (:>) to pass the symbol:

PassByOptionAlt["List" :> aList]
  • $\begingroup$ @Ajasja Always glad to help :). This question, by the way, should have been asked here long ago, since this is a common situation. $\endgroup$ Apr 22, 2013 at 22:26

This seems to do the job :

Attributes[PassByOption] = {HoldFirst};
PassByOption[opts___] := 
  With[{list = Hold["List"] /. Unevaluated[{opts}], 
        length = Range[Length["List" /. {opts}]]
      CheckboxBar[Dynamic[list], length] /. Hold[x_] -> x
aList = {1, 2, 3, 4, 5};
PassByOption["List" -> aList]

Unevaluated is used to prevent aList (from the option "List" -> aList) to be evaluated.

Warning : as Attributes[PassByOption] = {HoldFirst} the option "List" -> aList must be the first option when you call PassByOption


Just for fun here is a way to pass the reference as a string (I got this idea from @Leonids answer, but I'm not sure it brings anything useful over the injector pattern):

Here is the code:

        Function[l, CheckboxBar[Dynamic[l], Range@Length@l]
    , HoldAll]]

Check that it works:

aList = {1, 2, 3, 4, 5};
PassByOptionStr["List" -> SymbolName@Unevaluated@aList]

This is not directly related to the original question, but the next step is to test if the passed reference is valid. A convenient way to do this is using Leonids valueQ function. Apart from not leaking evaluations valueQ has some nice adavantages over the built in ValueQ. Compare for example:

{valueQ@{1 + 1}, ValueQ@{1 + 1}}

(* ==> {False, True} *)

Your Answer

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

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