30
$\begingroup$

Lately, and by lately I mean since version 7 or so, the number of atomic expressions in Mathematica constantly grew. In former times only the native types like integers and optimised arrays were atomic, but now we have Image, Graph, Association and many more.

The reason for this is mostly to make those structures highly performant. The big disadvantage is that it is not instantly visible what is atomic and that things like pattern matching, replacing, etc. don't work with them. A simple example is

Image[{{1, 0}, {0, 1}}] /. {0 :> {0, 1, 0}, 1 :> {1, 0, 0}}

The result is still a b/w image. When pattern matching doesn't work, I often give people the tip to look at the FullForm, but that doesn't help either. Those expressions look like something they are not.

Beside this obvious break with the one of the basic Mathematica paradigms, atomic expressions have advantages. One of those applications is when you use container expressions to store important information that should never be changed manually or bad things will happen. Let me give a simple example:

Assume you have a C++ library you use to calculate something and you need to manage a global object there. This object needs to stay alive for several callbacks from Mathematica. An easy way to achieve this is to not delete it and give a pointer to the object to Mathematica. So in Mathematica we have something like

LibraryObject[ptr->123456,state->"Initialised"]

Everyone should see that it is vitally important that no one changes the ptr to the object or the state. Therefore my question

Is it possible to make LibraryObject atomic like Image and protect it from access through [[]] from other changes?

$\endgroup$
  • 8
    $\begingroup$ Yes. Use System`Private`SetNoEntry on any expression which you want to protect in this manner. $\endgroup$ – Leonid Shifrin Oct 8 '14 at 13:42
  • $\begingroup$ @LeonidShifrin Is there a simple way to undo atomic? I know only HoldPattern@uncover@_@args__ := {args} and uncover@atomicExpr. $\endgroup$ – ybeltukov Oct 8 '14 at 13:58
  • $\begingroup$ @ybeltukov My impression is that, for a given expression, once done, this operation can't be undone. So, one would need to do some version of the "semi-deep copy", as you did. I may be wrong about this though. $\endgroup$ – Leonid Shifrin Oct 8 '14 at 14:07
27
$\begingroup$

Yes. Use

System`Private`SetNoEntry 

on any expression which you want to protect in this manner. This works on per-expression basis, so you have to apply this function to any instance which you want to protect. The result is a reference to the same expression.

The changes are performed in-place (no copy is created):

expr = h[1, 2, 3]

(* h[1, 2, 3] *)

AtomQ[expr]

(* False *)

System`Private`SetNoEntry[expr]

(* h[1, 2, 3] *)

AtomQ[expr]

(* True *)

This property belongs only to an expression to which the function was applied (of course, that extends to all places where you pass the reference to this expression). If you create a new expression with the same contents, you will have to perform the same procedure on it again. I stressed this subtlety, because we got used to think of expressions as stateless and immutable, but this particular operation actually mutates the expression (internally) and changes its internal state.

$\endgroup$
  • $\begingroup$ Why is this post CW? $\endgroup$ – Mr.Wizard Jan 19 '15 at 16:17
  • $\begingroup$ @Mr.Wizard Because I learned about this from someone else, and can't take the credit for this info. Most of my non-CW posts contain either programs I wrote myself, or things I've discovered myself rather than learned from another person. $\endgroup$ – Leonid Shifrin Jan 19 '15 at 17:30
  • $\begingroup$ You're even more amazing than I thought. $\endgroup$ – Mr.Wizard Jan 19 '15 at 17:44
  • $\begingroup$ Oh, c'mon, man, I'd never be even remotely as amazing as you :) I wouldn't even think that providing so many quality answers is humanly possible. $\endgroup$ – Leonid Shifrin Jan 19 '15 at 23:06
  • $\begingroup$ I am sincerely flattered. However mostly I just have time. If I followed your standard I think at least 80% of my answers would be CW. :-) $\endgroup$ – Mr.Wizard Jan 20 '15 at 2:55

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.