emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Save `nil' from the mutant void, preserve the truth of falsehood, preven


From: MON KEY
Subject: Save `nil' from the mutant void, preserve the truth of falsehood, prevent the falsehood of truth
Date: Sat, 11 Sep 2010 19:33:07 -0400

Two one-liners not even a Perl devotee could love:

(prog1 #1=(fboundp ()) (unintern #1#))

(prog1 #1=(intern-soft "") (unintern #1#))  ;; <- for the truly perverse

Approx. once per 1.5 weeks I find myself with a broken inadvertently uninterned
`nil' which leaves me with a semi-wedged Emacs session (usually this is a
singular session up since the last Emacs-crash/power-glitch).

Sometimes, I'm able to recover `nil' long enough to save the session, but even
then i've not any reasonable surety that the busted `nil' is a correct `nil'.

Other times a corrupted `nil' can so immediately frustrate Emacs' state that the
only safe solution is to put the old gal down ASAP.

Sans defadvice chicanery is there no explicit way to prevent
uninternment of the real `nil'?

emacs -Q

(sxhash nil)
;=> 19028

(intern-soft "nil")
;=> nil

(car nil)
;=> nil

(identity nil)
;=> nil

(fboundp 'nil)
;=> nil

(fboundp nil)
;=> nil

(fset 'nil  #'(lambda () (+1 1)))
;=> Debugger entered--Lisp error: (setting-constant nil)

(symbol-function 'nil)
;=> Debugger entered--Lisp error: (void-function nil)

(symbol-function nil)
;=> Debugger entered--Lisp error: (void-function nil)

(setq nil 'bubba)
;=> Debugger entered--Lisp error: (setting-constant nil)

(set 'nil 'bubba)
;=> Debugger entered--Lisp error: (setting-constant nil)

(unintern nil)
;=> t

(fboundp nil)
;=> Debugger entered--Lisp error: (void-variable nil)

(identity nil)
;=> Debugger entered--Lisp error: (void-variable nil)

(setq nil 'bubba)
;=> bubba

(identity nil)
;=> bubba

(car nil)
;=> Debugger entered--Lisp error: (wrong-type-argument listp bubba)

(fset 'nil  #'(lambda () nil))
;=> (lambda nil nil)

(symbol-function 'nil)
;=> (lambda nil nil)

(funcall 'nil)
;=> bubba

(funcall nil)
;=> Debugger entered--Lisp error: (void-function bubba)

(setq bubba nil)
;=> bubba

bubba
;=> bubba

(fset 'bubba #'(lambda ()))
;=> (lambda nil)

(funcall nil)
;=> nil

nil
;=> bubba

(setq nil (funcall nil))
;=> nil

nil
;=> nil

(symbol-value nil)
;=> nil

(set 'nil 'nil)
;=> nil

(sxhash nil)
;=> 19028

`sxhash' is all we've got... If I'm lucky the new `nil' is approximately
equivalent to the old `nil'.

Still, `sxhash' or no, the new `nil' is still extremely broken. To see
why see illustration below using `push' to turn `nil' into a list.

Apparently the uninternment of `nil' is not considered a "silly"
problem, e.g.  this comment in lread.c:

  /* There are plenty of other symbols which will screw up the Emacs
     session if we unintern them, as well as even more ways to use
     `setq' or `fset' or whatnot to make the Emacs session
     unusable.  Let's not go down this silly road.  --Stef  */

  /* if (EQ (tem, Qnil) || EQ (tem, Qt))
       error ("Attempt to unintern t or nil"); */

"Silliness" aside, I can't see how the above assertion is in
accordance with the manual.

,---- (info "(elisp)Standard Errors")
|
| `setting-constant'
|      `"Attempt to set a constant symbol"'
|      The values of the symbols `nil' and `t', and any symbols that
|      start with `:', may not be changed.
|      *Note Variables that Never Change: Constant Variables.
|
`----

"Never" is a long time and "may not be changed" sounds like a _promise_.

,---- (info "(elisp)Constant Variables")
|
| In Emacs Lisp, certain symbols normally evaluate to themselves.  These
| include `nil' and `t', as well as any symbol whose name starts with `:'
| (these are called "keywords").  These symbols cannot be rebound, nor
| can their values be changed.  Any attempt to set or bind `nil' or `t'
| signals a `setting-constant' error.  The same is true for a keyword (a
| symbol whose name starts with `:'), if it is interned in the standard
| obarray, except that setting such a symbol to itself is not an error.
|
`----

Apparently no one has bothered to tell the manual about `unintern'!

Or, maybe the manual _assumes_ that since other Lisp2's (e.g. Common
Lisp and forebears) thought it so it mus bet, and therefor didn't feel it
necessary to double check if this was kosher with the trash collector...

Indeed, it should be noted that CL implementations including CLISP, SBCL,
and CMUCL prevent (or otherwise make it very difficult) to unitern the
constants `t' and `nil'.

Yeah, I know, despite the Lisp-2'edness Emacs Lisp isn't CL...

So, how do the Schemes handle this? Is it possible to define/set away #f?

R5RS info says:
,----
| ,---- (info "(r5rs)Other notations")
| |
| | `#t' and `#f'.
| |  These are the boolean constants (section *note Booleans::).
| |
| `----
| ,---- (info "(r5rs)Literal expressions")
| |
| | As noted in section *note Storage model::, it is an error to alter
| | a constant (i.e. the value of a literal expression) using a
| | mutation procedure like `set-car!' or `string-set!'.
| |
| `----
`----

This said, Guile 1.9.10 doesn't seem to mind me let-binding `nil':

scheme@(guile-user)> (let ((nil 'bubba)) nil)
;=> bubba

Maybe this is because of some fundamental Lisp2 vs. Lisp1 tension around:
 (#t . t) (#f .  ) (nil . ())

Andy Wingo peered in on this recently:
(URL `http://lists.gnu.org/archive/html/guile-devel/2010-03/msg00077.html')

Still, Guile isn't nearly so promiscuous as to allow me equivocation with
impunity:

scheme@(guile-user)> (let ((#f #t)) #f)
;=> error
Good girl! Presumably other Scheme's are similar?

That Emacs lisp _pretends_ to not look kindly on a let-binding of
`nil' is even _worse_ than actually allowing me to do it:

(let ((nil 'bubba)) nil)
;=>  Debugger entered--Lisp error: (setting-constant nil)
Damn you Emacs lisp, when you lie to me I feel so cheap and used!

The error is in error, `nil' isn't a constant (not an immutable one anyhow).

Whatever, I understand that there are some GC issues w/regards marking
`nil' _truly_ special, but I simply can not understand how these
justify allowing uninternment of `nil'. Moreover the rationale for not
preventing it doesn't seem to jive with the fact that other Lisp
implementations of other Lisp dialects both Lisp1's and Lisp2's are
capable of preventing (and/or seriously restricting) the mutability of
falsehoods `nil', an `#f'.

By protecting the GC to the detriment of `nil' a nasty burden is
shifted onto the user which may cause her to doubt the truth of Emacs'
falsehood.

 "Nah, you can't trust ole Emacs... Gals trashy, and don't know how to
  tell the truth from da lies."

emacs -Q

(progn
  (unintern nil)
  (unintern 'nil))
;=>nil

nil
;=> Wrong type argument listp, nil

(set 'nil 'nil)
;=> nil

nil
;=> nil

(car nil)
;=> Wrong type argument listp, nil

(set 'nil ())
;=> nil

nil
;=> nil

(car nil)
;=> nil

(push '8 nil)
;=> (8)

nil
;=> (8)

Theres also this:

emacs -Q

(symbol-value (intern ""))
;=> Debugger entered--Lisp error: (void-variable )

(symbol-value nil)
;=> nil

(unintern nil)
;=> t

(set 'nil  (intern ""))

(identity nil)
;=>

Note, above thats not void its _nothing_ i.e. no return value!

As following illustrates:

(symbol-value nil)
;=> Debugger entered--Lisp error: (void-variable )

(let ((mv (make-vector 1 0)))
  (intern "" mv)
  (aref mv 0))
;=>

(unintern nil)

(set 'nil ())
;=> nil

(push 8 nil)
;=> nil

(unintern nil)
;=> Debugger entered--Lisp error: (wrong-type-argument stringp (8))

Most likely my arm waving won't avail to much and will fall on deaf
ears. Far more assertive arm waivers than I have failed to make the
case that saving `nil' is a worthwhile goal:

:SEE (URL `http://lists.gnu.org/archive/html/emacs-devel/2009-11/msg00298.html')

,---- RMS Sat, 14 Nov 2009 06:23:09 -0500
|
| As for their next pointers, if they are the first symbols to be
| interned, they are at the end of their obarray buckets, so their
| next pointers never need to be changed.  (We should make `unintern'
| check for t and nil and give an error.)
|
`----

,---- RMS Tue, 17 Nov 2009 02:57:08 -0500
|
|     I am skeptical that we have everything in place that is required
|     to properly support
|
|     (unintern nil)
|     (unintern t)
|
| We should make them give errors -- that's much easier than
| making them "work".  There's no reason they should be allowed
|
`----

,---- RMS Wed, 18 Nov 2009 07:11:39 -0500
|
| I will spend the time to make unintern give an error for t and nil.
|
`----

,---- RMS Thu, 19 Nov 2009 11:23:27 -0500
|
|     There are *many* ways for the user to shoot herself in the foot
|     and make her Emacs session completely unusable.
|
| We won't try all, but it is useful to catch some.  unintern is not
| used a lot, so don't worry about the cpu time.
|
`----

,---- CYD Fri, 20 Nov 2009 00:47:18 -0500
|
| (I sent an earlier email about this, but it seems to have gotten
|  lost.)
|
| FWIW, in CLISP and CMUCL (unintern nil) and (unintern t) are no-ops
| returning nil.  Presumably the other CL implementations do likewise.
|
| It seems to me that it'd do no harm to do likewise, but since others
| care strongly about this and I don't, I'll just shrug and go along...
|
`----

,---- Sam Steingold Sun, 22 Nov 2009 01:48:45 -0500
|
| i.e., it IS possible to remove the T symbol (with all the trouble this
| entails).
|
| As a CLISP maintainer, I don't think T & NIL are special enough.
| We lock entire packages.
| Please see <http://clisp.cons.org/impnotes/pack-lock.html>.
|
`----

,---- Dan Nicolaescu Thu, 19 Nov 2009 13:05:43 -0800 (PST)
|
| But not being able to unintern t and nil is not useful to anyone.
|
`----

,----  RMS Sat, 14 Nov 2009 06:23:16 -0500
|
| Sure, but even if it is only a small improvement for each person, it
| is still worth doing if it is easy.  Suppose that this small speedup
| transforms "annoying" into "not annoying" for just one user in a
| thousand each day.  That would mean that, each day, hundreds or
| thousands of people are happier.
|
`----

,---- RMS Sun, 15 Nov 2009 17:38:25 -0500
|
| Once in a while, this small speedup will be enough to make that
| difference for a particular person.  With so many users, it adds up.
| Also, several such small speedups do add up.
|
`----

Damn the speedup. The real cost savings is in not having to kill (and
recover from) a wedged/compromised Emacs session.

Whatever... Le roi est mort vive le éboueur!

--
/s_P\



reply via email to

[Prev in Thread] Current Thread [Next in Thread]