How to define a global variable when giving each notebook its own Context?

21

7

I have restricted the context of my notebooks to each individual notebook. So variables in each notebook are local and are not seen in another notebook.

But in two of my notebooks I have two functions that I want to plot simultaneously with the command Show. Please note that I want variables of each notebook to be local except for those two functions. So I need to define two global variables and then plot that two functions in Show. How can I define global variables in Mathematica?

MOON

Posted 2012-05-24T13:33:10.437

Reputation: 3 714

Answers

21

You can explicitly define variables in the global context by prefixing their name with Global`, for example, Global`i = 3 or Global`f[x_]:=x^2. However if you have set the notebook to have private context, you don't have Global` in your $ContextPath (in order to prevent interference from other notebooks with non-private context). Therefore in your notebooks the context Global` isn't really special, you can use any context, like myShared`. Indeed, that's desirable because that way you know that a third notebook will be unlikely to interfere.

So you would write in your first notebook

myShared`function[x_]:=x^2

and then could access that function from the other notebook as

myShared`function[3]
(*
==> 9
*)

Note that you can add your context to the context path by using

AppendTo[$ContextPath, "myShared`"]

This then allows you to refer to the function above without the prefix, e.g.

function[3]
(*
==> 9
*)

However note that with this, your local symbols may shadow the shared ones (however access as myShared`function still works even then), so you have to make sure that you don't use the unprefixed symbol in any way before the prefixed one was created.

You might consider avoiding the issue by using PrependTo instead of AppendTo, but then you are vulnerable to variable injection (including accidental one) from the other notebook. For example, imagine that you have the definitions

a = 3;
PrependTo[$ContextPath, "myShared`"]

and then you do in your other notebook

Begin["myShared`"]
function[a_] := a^2
other[a_] := 5
End[]

Let's assume the symbol a had not yet been used in that notebook, then it is created, together with the symbols function and other, in the context myShared`, and therefore in your first notebook now hides the local definition of a. That is, if you now evaluate a in your first notebook, the kernel will find myShared`a (without a value) first, and therefore use that instead of the local a; of course it won't evaluate to 3.

Yet another way to access the symbol without prefix would be the definition

function := myShared`function

which however only works in a context with evaluation. Especially it should not be used for shared variables because after

variable := myShared`variable

a subsequent assignment like

variable = 42

does not change the shared variable, but only the local one (which no longer refers to the shared one).

Therefore I think it is a better idea to not do either, but always use the prefixed version.

Note that the PrependTo scenario is also an argument against using Begin["myShared`"]End[] to simplify definitions in this case: It's too easy to accidentally introduce new symbols in that context which were not intended to be there.

Note that another way of sharing functions is to make them into a package and use that package from both notebooks. Ultimately this also boils down to having a shared context, as rcollyer noted in the comments. However a properly written package protects against or at least warns about most problems with hiding. Of course, writing a package might be overkill for your specific situation.

celtschk

Posted 2012-05-24T13:33:10.437

Reputation: 18 543

As written, myShared`function[a_]:=a^2 is not vulnerable as a is localized due to SetDelayed having the HoldAll attribute. – rcollyer – 2012-05-24T14:28:38.760

@rcollyer: No, it is vulnerable because the mere creation of that symbol already hides the local one. And yes, I've actually tested it. After defining the function in notebook 2, a in notebook 1 will no longer evaluate to 3, not because the value of notebook1uniquecontext`a has been overridden (that one still has the value 3 associated with it) but because that definition is hidden by the symbol myShared`a. Yes, that's a non-obvious effect, and exactly for that reason you should avoid it. – celtschk – 2012-05-24T14:34:53.137

Ah, I was executing it the same notebook and wasn't seeing the shadowing for what it was. My apologies. (Incidentally, this is simpler to demonstrate in a single notebook using cell grouping as the default.) That makes for a reasonable argument to 1. be careful with globals, in general, and 2. have the global context be last in $ContextPath to minimize its effects, i.e AppendTo v. PrependTo. I'm disappointed, though, that there isn't a shadowing warning raised. – rcollyer – 2012-05-24T14:43:55.730

@rcollyer: It can't raise a shadowing warning because in that notebook there's no other accessible symbol to be shadowed. If there were, the new symbol wouldn't have been created to begin with. – celtschk – 2012-05-24T14:49:30.450

So, by using PrependTo, you circumvent any checking capability, also. Well, that seals the case, then. Prepend for globals is bad. – rcollyer – 2012-05-24T14:56:08.943

Note that with AppendTo in the two-notebook case, you also can get a no-warning shadowing: Assume you try to refer to a shared function from the other notebook without context prefix, but forgot that you haven't yet executed the definition there. Thus you'll create a local context symbol. Then when defining in the other notebook, the symbol will be created in the shared context. However the already created local-context symbol in the first notebook will hide the newly-created shared symbol. However in the notebook creating the shared symbol, there's no shadowing and therefore no warning. – celtschk – 2012-05-24T15:09:29.070

I wasn't arguing with that point, and it falls under my admonishment "use globals with care" precisely because of problems like that. Specifically, elevating any namespace to the global namespace (using c++ terms) can introduce unintended and potentially unforeseeable consequences. So, I'd add the old nautical warning: "here be dragons!" to adding it to the $ContextPath. – rcollyer – 2012-05-24T15:22:06.837

Although, a two-tiered approach may work, i.e. have an inner context like myContext`Private which is not elevated, while exposing the needed symbols via f::usage in the outer context. But, at that point, you might as well call it a package, and be done with it. – rcollyer – 2012-05-24T15:22:37.353

@rcollyer: Yes, a package is exactly a set of shared functions in a separate namespace. I'll add that point to my answer. – celtschk – 2012-05-24T15:27:00.030

Since your answer is far superior, I'll delete mine. – rcollyer – 2012-05-24T15:29:13.333

thanks a lot . this command "myShared`function[x_]:=x^2" is the command that i have wanted and worked very well for me. – MOON – 2012-05-29T13:43:03.797

0

Globally define as follows $Assumptions = b >= 0 && c >= 0 && {u11, u13, u14} [Element] Reals then use globally defined variables as follows Simplify[expression with global variables]

user22889

Posted 2012-05-24T13:33:10.437

Reputation: 11

Hello and welcome to mma.se! Please note that the question is a bit more specific than the title suggests. The question would probably be too broad otherwise. The information you share is good to know, but I guess it is not really an answer here. – Jacob Akkerboom – 2014-12-02T12:10:53.853