Stefan Monnier wrote: >> I've removed «void». I recommend making makunbound stop working on >> non-globals too. > > `let' on dynamically-scoped variables doesn't make them non-local. > > Or rather, whether it does or not is a philosophical question (does > `let' create a new variable which shadows the outer one, or does it just > temporarily change the value of the variable?). Saying there's only a global variable doesn't remove the absurdity of makunbound within the extent of a «let». Suppose foo is currently unbound. Then: (defvar foo 0) ; Now foo is bound to 0 (let ((foo 1)) ; Now it's bound to 1 (makunbound 'foo)) ; Now it's bound to unboundedness ;; Now it's unbound from unboundedness, and thereby rebound to 0 You can't just say that makunbound in that case unbinds foo, because then the question arises, from what is foo unbound when the let-binding form exits? If foo were already unbound by makunbound, then there would be nothing left to unbind it from when «let» exits. Surely you can't say with a straight face that binding to unboundedness is not an absurd concept. Yet that's the alternative to the interpretation that Qunbound escapes as a special second-class value into the Lisp world. Either way, the behavior of makunbound is wrong. >>> - OLDVAL is either a list of one element containing the old value, or >>> nil (when that old value is Qunbound). >> Then run_varhook must cons. That'll generate a lot of garbage if you use it >> for profiling, or for debugging in a way where you don't just pause to >> inspect every hooked variable. Is that ok? > > I think it's OK, yes. This seems to be the least-bad option, so I did it this way, even though it makes the API a bit gross. Unfortunately, when you do: (require 'cl) (setq x 0) (symbol-hook 'x) (benchmark-run-compiled 100000 (incf x)) it now spends half the time doing garbage collection. That's a high price to pay to cater to the brain-dead misbehavior of makunbound. >> Or to avoid needing to cons in run_varhook, it could specbind something like >> Qsymbol_newval_void (to t if the new value is Qunbound), so the hook > > Yuck. That's even worse than using a value that is hopefully never > used elsewhere, like `::value--unbound::'. Then you'll probably also say ‟yuck” to my xref-push-mark patch that I posted to emacs-devel just now, since it uses that tactic. >> Would ⌜const_hooked⌝ be ok? > > How 'bout `writable' with values yes/no/thrufunction? That would make sense, but the meaning is inverted from how the code is written, e.g. the code has: if (constant) a...; else b...; so to account for the inversion, it would have to change to: if (!writeable) a...; else b...; which introduces an extra «not» operator. To avoid the extra operator, it would have to change to: if (writeable) b...; else a...; Usually the «a» ends with return, error, or xsignal1, which means no «else» is needed for «b», so changing the order to avoid the extra «not» operator would make the code more awkward. Since you think of variables as ‟vetted” if they might not be freely writeable, and the meaning of that term isn't inverted, I think ⌜vetted⌝ is the least-bad short name to replace ⌜constant⌝ in the places where it's used to mean «constant or hooked». (Where it means specifically «constant», i.e. the vetting is hardcoded to disallow writing, it still is called ‟constant”, e.g. in the standard macro SYMBOL_CONSTANT_P). Updated patch attached. BTW, I accidentally inlined a little too much for set_internal last time. This time I've factored out the part that doesn't need to be inline. This has no speed impact on the hot path, but it reduces the size of the executable by a few kB, and makes the source code a bit clearer too.