Previous | Table of Contents | Next |
Here is an example of and taken from the code for the function forward-paragraph, which is in the Emacs Lisp source file paragraphs.el.
The forward-paragraph command moves the cursor forward to the end of the current paragraph (this is the outcome we want, yet it is called a side effect).
The and expression is part of the varlist of a let* expression. (A let* expression is like a let expression, except that each element in the varlist is evaluated in sequence, and the values resulting from an earlier evaluation can be used later in the varlist.)
In the function definition for forward-paragraph, a variable called fill- prefix-regexp is given a value if and only if
10A fill-prefix consists of characters at the beginning of a line that are similar for all lines for a paragraph, such as blanks for an indent, or angle brackets for one form of email quotation. The use of a fill-prefix in forward-paragraph means that you can jump to the end of an indented paragraph, or the end of one marked on each line with > or another prefix.
Later in the function definition, the variable is used in an if expression, and, if it is not nil, the variable is also used to tell the command which lines are part of the paragraph and which are not.
Here is the and expression:
(and fill-prefix (not (equal fill-prefix )) (not paragraph-ignore-fill-prefix) (regexp-quote fill-prefix))
Here is what the parts mean:
The result of evaluating this and expression successfully is that fill- prefix-regexp is bound to the value of fill-prefix as modified by the regexp-quote function. regexp-quote reads a string and returns a regular expression that exactly matches the string and matches nothing else. This means that fill-prefix-regexp is set to a value that exactly matches the fill-prefix if the fill-prefix exists. Otherwise, the variable is set to nil.
An or expression is often used in a manner that is quite like an if expression. Here, for example, is an extract from the source for the insert-buffer function definition. insert-buffer is a command whose source is found in the simple.el file; the command inserts the contents of a second buffer into the current buffer.
The documentation says
Insert after point the contents of BUFFER. Puts mark after the inserted text. BUFFER may be a buffer or a buffer name.
The or expression checks whether the argument you pass to insert-buffer, which is the variable buffer, is a buffer or the name of one. (Note that the same symbol, buffer, is being used in two ways in this instanceeither as a buffer or as a name. If you are confused by the distinction between a buffer and its name, consider the difference between you personally being introduced to the editor of this volume and your name being mentioned to him. The former is you, the latter is a reference to you.)
The or expression in insert-buffer looks like this:
(or (bufferp buffer) (setq buffer (get-buffer buffer)))
The first argument to or is the expression (bufferp buffer).11 This expression returns true (a non-nil value) if the buffer is actually a buffer, and not just the name of a buffer.
11The p in bufferp stands for predicate. In the jargon used by early Lisp researchers, a predicate refers to a function that determines whether a property is true or false. bufferp determines whether it is true that its argument is a bufferhence this use of the naming convention.
If the argument is a buffer, the or expression returns this true value and does not evaluate the next expressionand this is fine because the commands do not want to do anything to the value of buffer if it really is a buffer.
On the other hand, if the value of (bufferp buffer) is nil, which it is if the value of buffer is the name of a buffer, the Lisp interpreter evaluates the next element of the or expression. This is the expression:
(setq buffer (get-buffer buffer))
This expression returns a non-nil value that is the value to which it sets the variable bufferand this value is a buffer itself, not the name of a buffer.
The result of all this is that the symbol buffer is always bound to a buffer itself rather than to the name of a buffer. All this is necessary because the next part of the code (not shown here) works only with a buffer itself, not with the name of a buffer.
As for or being like if, the expression could have been written like this:
(if (not (bufferp buffer)) (setq buffer (get-buffer buffer)))
This would have produced the same result, but is longer and less elegant.
Emacs Lisp has two primary ways to cause an expression, or a series of expressions, to be evaluated repeatedly: One uses a while loop, and the other uses recursion.
Repetition is valuable. For example, to move forward four sentences, you need only write a program that moves forward one sentence and then repeats the process an additional three times.
In Emacs Lisp, while loops are used more frequently than recursion because they tend to be faster. (In some other dialects of Lisp, recursion is as fast as or faster than while loops.)
Previous | Table of Contents | Next |