2

One moment I decided to assign symbolic names to all special spaces since they all look the same when put literally in FrontEnd editor, more or less like "" or " ".

I wrote the following macro:

Block[{Set}, Set @@@
( MapAt[
    Composition[Symbol
    , StringReplace[#, "[" | "]" | "\"" | "\\" ] -> ""]& ]
  , #, {1}] & /@
  Select[
    {ToString@FullForm@#, #} & /@
    FromCharacterCode /@ (-1 + Range[2^16])
  , StringMatchQ[First@#, ___ ~~ "Space]\""] &] ) ];

that checks all Unicode chars recognised by Mathematica as “smth-Space”, fetches symbol names and performs the assignments. After macro expansion I expect to get

Block[{Set}, Set @@@
{ { NonBreakingSpace, " " }
, {       ThickSpace, " " }
, {        ThinSpace, " " }
,            (…rest)        }]

However, while the expression in round brackets does evaluate to correct table of symbols and various spaces if evaluated independently, and Set@@@ on it works perfectly well, the whole macro Block[{Set}, …] starts throwing lots of errors, from $RecursionLimit and ToExpression. (Being a bit too hasty, I put it into pre-loaded packages — naturally, it made Kernel crash every time I attempted to start it.)

That said, Block[{set}, set@@@(…) /. set -> Set] works OK, but the question remains: what causes the problem in the original macro? This is not the first time I make assignment with Block[{Set}, Set@@@table];, and I would like to keep doing it further. The issue is surprising.

The only explanation I see is that Blocking Set somehow interferes with evaluating the expression in round brackets (the one meant to evaluate to the table). But this behaviour is quite unexpectable unless I miss something obvious, and there also does not seem to be a way to trace the evaluation.

1) Is there a way to Trace the evaluation?

2) What really causes the problem? (In case it is possible to find out at all without cracking the kernel.)

akater
  • 1,540
  • 11
  • 16
  • 2
    Blocking Set is a really bad idea, unless you want to block everything else inside Block as well, to make the code completely inert. You never know what system functionality will be affected, but with a function as fundamental as Set, you can be sure that some will. This kind of code / changes are enough for me to not be willing to spend any time looking deeper, don't know about the others. – Leonid Shifrin Apr 07 '14 at 17:44
  • I agree with @LeonidShifrin. Also see this relevant discussion: http://mathematica.stackexchange.com/q/1162/5 (possibly even a duplicate) – rm -rf Apr 07 '14 at 18:10
  • @LeonidShifrin Set is a pure side-effect, a modification of environment. So, I'd say that, on the contrary, blocking it of all things should not affect anything at all, unless the environment is modified with it internally on a regular basis… but it goes contrary to everything I know about Mma, to be honest. If you say rules do get rewritten routinely under the hood I'll just accept it, sure, and delete the question if needed. But it's definitely not clear why blocking Set is a bad idea unless someone with insider knowledge just postulates this. – akater Apr 07 '14 at 21:24
  • @rm-rf Thanks. “It [Set] could have been already overloaded internally for certain purposes.” — Ah, I see. That is something I had not thought about, and it could explain a lot. (This would be the first big disappointment in the core language for me, though.) I'm ready to delete this Q. – akater Apr 07 '14 at 21:31
  • 1
    @Akater The problem is that the system is neither completely side-effect-free (can't be) nor based exclusively on side effects. The real problem is that it is symbolic. What this means is that at certain point, some functions may expect to get arguments with certain heads or, generally, certain structure. By blocking Set, you delay assignments to some variables / L-value-expressions. If those expressions are passed to some functions, those functions are not getting what they would expect to get at that stage. In more traditional languages, calling an undefined function (Set here) would ... – Leonid Shifrin Apr 07 '14 at 21:45
  • @Akater ... be an error. In Mathematica, it is not, because it is symbolic, but the problem shows up in a different way. To put in another way, by Block-ing Set you change the evaluation sequence for internal functions (which use Set) in a way they weren't designed to handle. In most languages, you can't even do anything as fundamental as changing the semantics of core operations such as assignments via dynamic scoping, for a part of execution stack rather than a part of the source code. This is a fairly disruptive / intrusive change, it is even much worse than things like AOP. – Leonid Shifrin Apr 07 '14 at 21:50
  • @Akater And yes of course, "the environment is modified with it internally on a regular basis". Mathematica is not a pure functional language, mutations are very much allowed (even if not admired). Any function which uses Module, Block, or even CompoundExpression, does that - because it makes no sense to use these functions if you don't have side effects in that code. And of course, a lot of internal functions use those constructs, because Mathematica is largely written in itself. If you had a picture of Mathematica being pure stateless rewrite system, that's a wrong picture. – Leonid Shifrin Apr 07 '14 at 21:54
  • @Akater And the fact that most of the functions exposed to the user operate on immutable expressions does not mean that their implementations don't contain mutable state. – Leonid Shifrin Apr 07 '14 at 21:55
  • @Akater Regarding deletion - I don't have a strong opinion on the matter. You raised an important issue, and this has not been discussed here on M SE in any significant detail before. Probably, many other folks do have similar questions. So, it may be a good idea to keep this. Let's see what others think. – Leonid Shifrin Apr 07 '14 at 21:56
  • @LeonidShifrin Thank you! No, I didn't think of Mma as of purely immutable. User actually has almost complete control over the core state, and that's why I expected it to be as inert in the absense of user as possible. Given this commentary of yours, I don't want to delete the question anymore. :-) So yes, let's wait. – akater Apr 07 '14 at 22:07
  • @Akater Another source of confusion may come from comparisons with Lisp etc. Mathematica does not have well-defined read or compile-time. So, in practice, what you call a macro is in fact a dynamic environment, which means that, rather than just expanding code, it changes the state of the system for a (part of) the execution stack, and that's a very unsafe operation. You can also write true macros in Mathematica, but they would involve lexical rather than dynamic scoping constructs, such as With, Function, or replacement rules - as well as tools of evaluation control (Hold and friends). – Leonid Shifrin Apr 07 '14 at 22:13
  • 1
    @Akater " User actually has almost complete control over the core state, and that's why I expected it to be as inert in the absense of user as possible" - well, let me then put it differently. If we think of Mathematica as a rewrite system, then it is well-known that the rules are non-commutative, in the sense that the result depends on the order in which rules are applied. Set can be thought of as a constructor of global rules (which it is). By Block-ing it, you change the sequence in which global rules are constructed, which is equivalent to changing the order in which they are applied – Leonid Shifrin Apr 07 '14 at 22:17
  • @Akater "This would be the first big disappointment in the core language for me, though." - as far as I know, internal overloading of Set is very infrequent and thought of as a last resort. It is almost just as bad to do that internally as when done by the end user, because any two such modifications done independently can conflict in hard to predict ways, and because it hinders the generality of the language. So, I wouldn't get disappointed just yet - a lot of thought has been put into the design of every (core) feature, and, at least in my view, there are very few inconsistent places. – Leonid Shifrin Apr 07 '14 at 22:30

0 Answers0