18
$\begingroup$

The only official info about $CellContext` I was able to find is:

placeholder for the context of a symbol inside Dynamic

from StandardNamespaces

I have some intuitive understanding how it works but I would like to know more and for sure.

Can someone explain authoritatively what is the purpose of it. And if there is possibility to manually use it for something useful?

$\endgroup$
11
$\begingroup$

Somehow I've overlooked this topic on MathGroup earlier: $CellContext

Here's what John Fultz said:

$CellContext is a symbolic placeholder in cell expressions (most typically Dynamic expressions inside of Cell) which indicates that the ambient context as defined by the CellContext option should be used (which allows you to wall off notebooks, cell groups, and cells from each other via automatically generated contexts).

This is to distinguish from the default kernel context, which would be $Context.

For example:

CellPrint[ExpressionCell[Dynamic[Context[a]], "Output"]]
CellPrint[ExpressionCell[Dynamic[Context[a]], CellContext->"Private`","Output"]]
CellPrint[ExpressionCell[Dynamic[Context[a]], CellContext->Cell,"Output"]]
Global`
Private`
Cell$$3566`

You'll see it a lot in cell expressions, but it's supposed to be replaced with the actual context whenever an operation goes to the kernel. It's possible that this was overlooked in some cases.

$\endgroup$
  • $\begingroup$ Keep in mind that this is an old post. $\endgroup$ – Kuba Feb 8 '15 at 19:40
11
$\begingroup$

And if there is a possibility to manually use it for something useful?

Yes, it solves a problem I had many times and which I had to work around. And none of those work arounds was as general as a following method.

The case

  • you are writing a package that exports a function GenerateModule[] which creates new notebook/cdf. (let's say each instance has to import data, do something fancy and plot it with some additional interactive functionality)

  • Each instance of such generated notebook has to be independent, not interfere with others, so it should be properly scoped.

Small issue

  • it would be nice to share variables from main module with DockedCells of our CDF, but still have them scoped.

Big issue

You can say, what's the problem, use DynamicModule and don't do anything stupid. But:

  • CDF is working based on some relatively big data, or will import quite big file. And from my experience DynamicModule variables are not designed for that.

    Large variables at some point are causing a worse performance of the FrontEnd. The same issue happens in case of storing data in notebook's TaggingRules. They just can't handle it.

  • Other scoping constructs like Module are useless because we need to work interactively with data, it's not just one evaluation.

Ok, so we are forced to use standard Kernel variables. Let's use a context local to the notebook!

  • But how to write a package designed for using notebook's local variables?

    During read time of the package all symbols will get current context, like Project` or Project`Private`. Even those unevaluated.

The answer is - using $CellContext`!

Example

BeginPackage["Project`"];

    GenerateModule;

Begin["`Private`"];

    GenerateModule[] := CreateDocument[
        DynamicModule[{},
            {Button["inc.", $CellContext`x++], 
             Dynamic@$CellContext`x}
            ,
            Initialization :> (
                $CellContext`x = Range@5;
            )
        ],
       CellContext -> Notebook
   ];

End[];

EndPackage[];

Now call GenerateModule[] twice. Each notebook looks similar but clicking buttons doesn't affect others! Try definig GenerateModule without $CellCOntext, now each click updates all notebooks because x is in Project`Private` context as it was read.

So assuming you can't scope x in DynamicModule there isn't any solution that would be so simple. One could work with ToExpression and strings, but that's just ugly.

Additional notes

  • Variables scoped in DynamicModule can be synchronized/shared with DockedCells and rest of outside world. (InheritScope etc) but it isn't so flexible. Now it is :)

  • For interface/debugging purposes you can just make your cdf editable and start typing below the module. It isn't fully transparent now but good enough for me.

$\endgroup$
7
$\begingroup$

I have been thinking recently a lot about this mysterious $CellContext, that turns up when we convert a cell with interactivity (such as Button, Slider, DynamicModule, Dynamic) to a cell expression. Just as Kuba, I found that there is not much documentation on this topic, but in MathGroup and SE there are some very valuable comments and remarks, not in the least from John Fultz.

Here I will try to formulate my ideas how it works. I want to emphasize that I created only a model for Mathematica, based on a lot of testing small examples. Only the developers of Mathematica know if this model describes the reality.


Everything that is seen on the screen is under control of the frontend. When we enter something on the keyboard, the frontend typesets our input in boxes. When we press shift-enter, these boxes are send to the kernel. The kernel uses MakeExpression for making an expression of the input, evaluates that expression, then calls MakeBoxes and sends back the boxes to the frontend. The frontend the displays these boxes, and that is what we see as output. LinkSnooper clearly shows this.

So the kernel only knows about expressions, the frontend only knows about boxes. The frontend cannot know anything about the expressions and variables that were used by the kernel for the construction of the boxes that are sent by the kernel for the output!

A simple example. Evaluate

Slider[0.5]

LinkSnooper shows that BoxData are send to the kernel, and the kernel returns BoxData with a SliderBox with argument 0.5 to the frontend. Then move the slider and convert the output cell to a CellExpression. That is completely done by the frontend; LinkSnooper does not show any traffic between the frontend and the kernel. So the CellExpression is computed by the frontend, using the frontend variable that controls the position of the Slider. Indeed, in the SliderBox we see the current position of the slider. The argument of the SliderBox corresponds to a frontend variable.

It is more general: when we construct a graphical user interface (GUI) with a kernel command GUI[f[x1, ..., xn], the state of this displayed GUI will depend on n state variables, all belonging to the frontend, of which the initial values are given by x1, ..., xn. (Here GUI can be Slider, Button, Dynamic, DynamicModule, ...)

As we have seen already in the slider example, it is important to observe that there is no synchronization between the kernel variable that was used to generate the graphical user interface and the corresponding state variable in the frontend. Synchronization can be established by using the kernel command Dynamic. When a GUI is constructed with a kernel command with a kernel variable wrapped in Dynamic, then this kernel variable and the corresponding state of the GUI are synchronized. And that is the situation when $CellContext variables turn up.

Here I will only look at the example with the slider:

x=0.5; Slider[Dynamic[x]]

Inspect the cell expression. It looks like

Cell[BoxData[
 DynamicBox[ToBoxes[
   Slider[$CellContext`x], StandardForm],
  ImageSizeCache->{300., {12., 21.}}]], "Output"]

Here we see a $CellContext`x variable. It synchronizes the position of the Slider (which belongs to the frontend) with the kernel variable x. The argument of the Slider is the value of the frontend variable controlling the position of the slider. It is replaced here within a DynamicBox with the variable $CellContext`x.

In a DynamicModule we may have $CellContext variables that do not immediately correspond to a kernel variable. Consider the example

DynamicModule[{x = 0}, x = x + 1; Button["x", x = x + 1; Information[x]]]

The CellExpression shows a variable $CellContext`x$$. But when we press the button, we see a kernel variable FE`x$$15 or something like that. This seems to be a particular case of the following:

When with respect to a frontend variable $CellContext`x$$ the frontend has to call the kernel, it will create a special kernel variable FE`x$$nn in the context FE`.

This mechanism is used often for variables in a displayed DynamicModule.


So to summarize: I think that $CellContext variables are very special kernel variables, that only turn up in CellExpressions of displayed GUIs. They always correspond to a frontend variable of the displayed interface, and may or may not immediately be linked to a normal kernel variable. I think that is all. In the documentation, $CellContext is said to be a placeholder. Placeholder for what? I think a placeholder for a frontend variable, anyway not for anything belonging to the kernel.

Any remarks on these ideas are highly appreciated.

$\endgroup$
  • $\begingroup$ There are Java/C variables in terms of FE and Kernel so saying that Slider[0.5] argument coresponds to one is understandable but then I feel like I'm confused reading this by the border between such variables and symbols in MMA. $\endgroup$ – Kuba Feb 9 '15 at 20:33
  • $\begingroup$ But Cell[BoxData[ SliderBox[Dynamic[x]]], "Output"] acts exactly the same as Cell[BoxData[ SliderBox[Dynamic[$CellContextx]]], "Output"]` ... $\endgroup$ – Rolf Mertig Feb 9 '15 at 20:59
  • $\begingroup$ @Kuba. In my perception there are no symbols in Mathematica as such. Mathematica consists of two programs, the frontend and the kernel, each having their own set of variables. For me, that distinction turned out to be very useful for understanding graphical user interfaces. The documentation of Mathematica nearly everywhere discusses only kernel variables. $\endgroup$ – Fred Simons Feb 10 '15 at 8:19
  • $\begingroup$ @Rolph. It makes a difference if you copy and paste the kernel expression Cell[BoxData[ SliderBox[Dynamic[x]]], "Output"] in a notebook and let the frontend interprete the expression, or if you evaluate CellPrint[Cell[BoxData[ SliderBox[Dynamic[x]]], "Output"]]. For the user, the two sliders look identical. But the CellExpression of the first slider has only a Dynamic[x], whereas the second one does have a $CellContext`x. Remarkable, indeed $\endgroup$ – Fred Simons Feb 10 '15 at 8:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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