4
$\begingroup$

For certain persistence locations, such as "Notebook" or "FrontEndSession", Once adds $CellContext` to all Global` symbols, e.g.

Once[x, "Notebook"]

after the second evaluation (when the persistent object has been created) will only give

$CellContext`x

and not just x.

I'm sure there's a good reason for this (avoiding collisions), but I see two problems at the moment:

  1. The obvious problem that all names of symbols are now changed.
  2. In my case, in place of x I have an expression that returns a fairly long result, and the addition of $CellContext` to each symbol name blows up the stored result unnecessarily.

How can I get Once not to add $CellContext` to every symbol name?

I have already tried some tricks such as Block[{$Context = "System`"}, …] (as in Exporting notebooks inserts unwanted $CellContext. Workaround?), but Once appears to be treatment-resistant.

(I'm aware that one can access and change the content of the corresponding PersistentObject and in this way manually remove the added context, but this seems like a risky brute force solution to me.)

$\endgroup$
4
  • 1
    $\begingroup$ i think maybe you should report this as a bug to wolfram support? it certainly seems like Once[...] should produce the same output on each subsequent evaluation as it did for its first evaluation—that's its whole deal! In the meantime...hmmm. Maybe you could remove the $CellContexts forcibly after evaluation as a workaround? Might defeat the point of Once though... $\endgroup$
    – thorimur
    Commented May 16, 2022 at 5:53
  • $\begingroup$ @thorimur Yeah, as mentioned I'm sure you can try to find the PersistentObject after creation (although I'm not sure how the hashes are created) and then change the value inside PersistentObject[…]["Value"]. Seems risky to me. I think the main problem is that Once is hard to control — compare how in the answer I referenced there was indeed a solution with Block that doesn't work here. $\endgroup$
    – Deniz
    Commented May 16, 2022 at 6:00
  • 1
    $\begingroup$ Just out of interest I tried to crack the hashes. I can't quite figure them out, but i'm fairly sure it's what you get when you take the default "Expression" type hash of some expression (not sure which) as an 8-byte bytearray, then convert it to base 64 and trim leading zeros. The hashes use the characters 0-9, a-z, A-Z, "-", and "_" for a total of 64 characters to encode the resulting base 64 number—not sure exactly how, either, but hashes always seem to be between 10 and 11 characters, and Log[64, (16*16)^8] is 10 and 2/3. $\endgroup$
    – thorimur
    Commented May 16, 2022 at 8:26
  • $\begingroup$ I can confirm that this is still a problem with Mathematica 14. It also caused me no end of grief. $\endgroup$ Commented Feb 20 at 3:01

1 Answer 1

1
$\begingroup$

I don't have a solution, only a workaround:

undoCellContext[expr_] := Module[{ccSymbols, rules},
  ccSymbols = 
   Cases[expr, _Symbol, \[Infinity]] // DeleteDuplicates // 
    Select[StringStartsQ["$CellContext`"]@*ToString];
  rules = (# -> Symbol["Global`"<>SymbolName[#]]) & /@ ccSymbols;
  expr /. rules
  ]

Once[...,"Notebook"] // undoCellContext

As an optimization, when LeafCount[expr] is suitably large, undoCellContext could switch from building a list and deleting duplicates to populating a HashSet within the delayed rule given to Cases.

It would also perhaps help if undoCellContext held the expression, and the replacement symbols, unevaluated until it was done with it.

We could "Fix" Once on versions where it's misbehavinbg:

If[$VersionNumber<=14.,
  Unprotect[Once];
  Once`Private`$overridden = True;
  Once[expr__,"Notebook"] := Block[{Once`Private`$overridden = False},
    Once[expr, "Notebook"] // undoCellContext
  ] /; Once`Private`$overridden
  Protect[Once];
]

For reference, Once is not guilty. The underlying problem is that PersistentObject[...,"Notebook"]["Value"] converts Global</code> symbols to <code>$CellContext on readout.

$\endgroup$

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.