How to delete variable/forms in Lisp?
Asked Answered
F

4

24

In Python we have the del statement for deleting variables.

E.g:

a = 1
del a

What the equivalent of this in Lisp?

(setq foo 1)
;; (del foo) ?
Foliose answered 20/1, 2014 at 10:40 Comment(7)
This looks like a XY problem. The occurrences of need for such a pattern should be quite scarce.Pooi
@Pooi Don't know if it's that kind of a problem. But I had been feeling the need of such a thing for quite sometime while fiddling around with my Emacs. And hence the question. Scrace, I don't think so.Foliose
if you intended it for elisp, you should have tagged it as such.Korfonta
@WillNess Well, I wanted to know how it's done in Lisp in general. And based on that finding the elisp equivalent is trivial.Foliose
no such thing as "Lisp in general". In pure functional Lisps there would be no set! at all, much less makunbound.Korfonta
@WillNess Excuse my limited knowledge of Lisp and it's different dialects. Plus I have no idea what set! is.Foliose
all I'm saying is, use more tags. :) Both "Lisp" and "Elisp" would be entirely appropriate to use, when originally posting. The more details you can provide, e.g. by mentioning Emacs in the question body itself, the more it helps, to answer it better. :)Korfonta
L
31

In Common Lisp.

For symbols as variables:

CL-USER 7 > (setf foo 42)
42

CL-USER 8 > foo
42

CL-USER 9 > (makunbound 'foo)
FOO

CL-USER 10 > foo

Error: The variable FOO is unbound.

See:

  • MAKUNBOUND (defined)
  • SLOT-MAKUNBOUND (defined)
  • FMAKUNBOUND (defined)
Lumpen answered 20/1, 2014 at 11:23 Comment(2)
My Steel Bank Common Lisp does not know the function makeunbound. (apropos 'makeunbound) also yields nothing.... Probably because the inventor of this glorious function had a damaged 'e' key on their keyboard and named it makunbound o.OChantey
Note that makunbounding a dynamic variable does not keep it from interfering with lexical variables of the same name - another reason to stick to the *earmuffs* convention so you never have lexicals and dynamics with the same name.Prevent
S
14

Python names reside in namespaces, del removes a name from a namespace. Common Lisp has a different design, one much more sympathetic to compiling efficient code.

In common lisp we have two kinds of "variables." Lexical variables account for the majority of these. Lexical variables are analogous to a C local. At runtime a lexical variable usually is implemented as a bit of storage (on the stack say) and the association with it's name is retained only for debugging purposes. It doesn't really make any sense to talk about deleting lexical variables in the sense python uses because the closest analogy to python's namespace that exists for lexical variables is the lexical scope, and that purely an abstraction used by the spec and the compiler/evaluator.

The second variable kind of "variable" in CL are "global" symbols. Symbols are very rich data structures, much richer than a label in python. They can have lots of information associated with them, a value, a printed name, their "home" package, a function, and other arbitrary information stored in a list of properties. Most of these are optional. When you use a name in your source code, e.g. (+ X 3), that name X will usually denote a lexical symbol. But failing that the compiler/evaluator will assume you want the value of the "global" symbol. I.e. you effectively wrote (symbol-value 'X) rather than X. Because of typos, programming conventions, and other things some decades ago the compilers started complaining about references to "global" symbols in the absence of a declaration that signaled that the symbols was intended to be a "global." This declaration is known as "special." Yes it's a stupid bit of nomenclature. And worse, special variables aren't just global they also have a very useful feature known as dynamic binding - but that's another topic.

Symbols that are special are almost always declared using defvar, defparameter, or defconstant. There is a nearly mandatory coding convention that they are spelled uniquely, i.e. *X* rather than X. Some compilers, and most developers, will complain if you deviate from that convention.

Ok. So now we can get back to del. Special variables are denoted with a symbol; and this is analogous to how in python variables are denoted with a name. In python the names are looked up in the current namespace. In Common Lisp they are looked up in the current package. But when the lookup happens differs. In python it's done at runtime, since names can by dynamically added and removed as the program is running. In Common Lisp the names are looked up as the program is read from a file prior to compiling it. (There are exceptions but let's avoid thinking about those.)

You can remove a symbol from a package (see unintern). But this is an rare thing and is likely to just make your brain hurt. It is a simple operation but it get's confusing around the edges because the package system has a small dose of clever features which while very helpful take a bit of effort to become comfortable with. So, in a sense, the short answer to your question is that for global symbols the unintern is the analogous operation. But your probably doing something quite exceptional (and likely wrong) if your using that.

Sigfried answered 20/1, 2014 at 15:59 Comment(1)
Imho, one of the clearest explanations I have read on a Lisp feature. Thanks.Buckram
H
4

While what @Ben writes is true, my guess is that what you are looking for is makunbound, not unintern. The former does not remove the symbol from the obarray (for Emacs Lisp) or package (for Common Lisp). It just removes its symbol-value, that is, its value as a variable. If you want the behavior that trying to get the variable value results in a not-bound (aka void) error, then try makunbound.

Hasa answered 21/1, 2014 at 3:53 Comment(0)
O
1

I am not contradicting the previous answers but adding.

Consider that Lisp has garbage collection. As you know, you get a symbol defined in many ways: setf, defvar, defparameter, make-symbol, and a lot of other ways.

But how do you get a clean system? How do you make sure that you don't use a variable by mistake? For example, you defined abc, then later decided you don't want to use abc. Instead you want an abc-1 and an abc-2. And you want the Lisp system to signal error if you try to use abc. If you cannot somehow erase abc, then the system won't stop you by signalling "undefined" error.

The other answers basically tell you that Lisp does not provide a way to get rid of abc. You can use makunbound so that the symbol is fresh with no value assigned to it. And you can use unintern so that the symbol in not in any package. Yet boundp will tell you the symbol still exists.

So, I think that as long as no other symbol refers to abc, garbage collection will eventually get rid of abc. For example, (setf pt-to-abc abc). As long as pt-to-abc is still bound to the symbol abc, abc will continue to exist even with garbage collection.

The other way to really get rid of abc is to close Lisp and restart it. Doesn't seem so desirable. But I think that closing Lisp and starting fresh is what actually gets rid of all the symbols. Then you define the symbols you want.

You probably usually want makunbound, because then, the system will signal error if you try to add the value of abc to something else because abc won't have any value. And if you try to append abc to a string, the system will signal error because abc has no string. Etc.

Oho answered 21/11, 2017 at 3:39 Comment(1)
"You can use makunbound ... And you can use unintern ... Yet boundp will tell you the symbol still exists." That is absolutely not the case in elisp, FWIW.Derivative

© 2022 - 2024 — McMap. All rights reserved.