29

I have seen progn being used quite a lot as I browse the configuration files of experienced Emacs users. I found this nice explanation of progn, but what I am really curious about is, what is the benefit of using this function? Take for example this snippet (taken from Sacha Chua's configuration):

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

Is there any major difference between the above configuration and this?

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t))

I feel like the first example is somehow cleaner, even though it has more syntax, and my intuition is that there might be some kind of performance boost from using progn, but I am not sure. Thank you for any insights!

mustaqim
  • 47
  • 6
elethan
  • 4,755
  • 3
  • 29
  • 56
  • 9
    In this particular case there is no difference: `use-package` will wrap a `progn` around your :config forms if it is missing. Try it out: you can put point at the end of a `(use-package ...)` and call `M-x pp-macroexpand-last-sexp` to see how the macro is expanded. You'll see that it is identical for these two examples. – glucas Dec 03 '15 at 04:23
  • An example where `progn` is needed: https://emacs.stackexchange.com/questions/39172/emacs-lisp-let-with-while – npostavs Mar 03 '18 at 23:58

3 Answers3

19

progn is typically used when dealing with macros. Some macros (use-package is a macro, last I checked) accept only 1 form, where others consume all remaining forms.

progn is used in the former case to turn a sequence of forms into a single form.

In your examples, the first one uses progn and thus there is 1 form after :config. In the second, there are 3 forms. If the use-package macro only expects 1 form following :config, then it will cause an error.

It is worth noting that using progn works in both cases, while omitting it only works if the macro accepts multiple forms. As a result of this, some people prefer to simply always use progn, because it will always work.

J David Smith
  • 2,635
  • 1
  • 16
  • 27
  • 21
    It really has nothing to do with macros. Some functions and macros have a so-called "implicit `progn`", meaning that they accept any number of sexps as separate arguments and evaluate them in sequence. Others don't, and instead expect/allow only a single argument where you might want to evaluate multiple sexps in sequence. That's all `progn` does: it lets you provide a single sexp that when evaluated evaluates the sexp args to `progn` in sequence. Compare `(if true (progn a b c))` with `(when true a b c)`. In both cases, `a`, `b`, and `c` are evaluated in sequence. – Drew Dec 03 '15 at 05:40
  • 1
    @Drew: which is what I said. "implicit `progn`" -> "consume all remaining forms". I reached to macros as an example because that covers 99% of use cases and makes for a clear answer. I considered adding a note pointing out that `progn` isn't *just* for macros, but I didn't feel it added to the answer. There are other use cases, but they are rather uncommon. – J David Smith Dec 03 '15 at 05:42
  • 2
    `use-package` [allows multiple forms in `:config` and `:init`](https://github.com/jwiegley/use-package#byte-compiling-your-emacs). –  Dec 03 '15 at 11:06
  • 8
    I disagree that 99% of the use cases are for macros etc. **Any function or macro** can be passed a `progn` sexp that contains multiple sexps that are evaluated for their side effects, before returning the result of the last of these. It really has nothing to do with macros. Macros "as an example" is fine. Giving the impression that `progn` exists for macros, and that 99% of its use is for macros, is misleading, IMO. `progn` is about shoveling a **sequence** of evaluations into a **single** sexp (to fit a given expected argument), and it is therefore about **side effects**. – Drew Dec 03 '15 at 14:47
  • @Drew glad you made that clarification here; anyone reading the accepted answer should read your comments first. – Emacs User Dec 03 '15 at 15:36
  • @Drew: I can't think of any time I've used `progn` except for as the input to a macro. Can you give an example of where it'd be used aside from as input to a macro or special form? I don't follow your logic about it being about side effects. – J David Smith Dec 03 '15 at 16:20
  • 5
    1. `progn` was introduced in [**Lisp 1.5**](http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf) (see section *The Program Feature*), in 1962, *long* before macros were added to Lisp. The purpose is to sequentially evaluate expressions for their side effects. 2. See [`progn`](http://www.gnu.org/software/emacs/manual/html_mono/eintr.html#progn) for how *Emacs itself* introduces `progn` to Elisp programmers. See the [`zap-to-char`](http://www.gnu.org/software/emacs/manual/html_mono/eintr.html#zap_002dto_002dchar-body) code for a simple use case. – Drew Dec 03 '15 at 17:42
  • 1
    @Drew: while I understand your point now, I don't believe that's the way to answer this question. Even though that was the original intention, in my experience it is very rarely used in that fashion these days. Most of the examples one will encounter when seeing elisp are of `progn` to pass multiple forms as a single form. The fact that it originally did this to explicitly order forms for their side-effects is not particularly relevent *in emacs lisp*, even if it is still relevant in other lisps – J David Smith Dec 03 '15 at 22:40
  • 1
    @Drew: as an aside: the ordering of lisp forms is implicit in emacs lisp and the usage for side effects is obvious (by virtue of the fact that otherwise it wouldn't be useful for the main use case in emacs). I don't think that the definition of what progn *is* accurately depicts *what we now use it for* – J David Smith Dec 03 '15 at 22:41
  • 3
    We can agree to disagree. My point is that `progn` has *nothing whatsoever to do with macros.* Its purpose is of course "*to pass multiple forms as a single form*" (your words) - whether to a function or a macro or a special form, but also to "*Eval BODY forms sequentially and return value of last one*" (doc string). **Now** as ever ("these days", indeed!). An ordered evaluation is important only for side effects, obviously. A given use case (macro or not) might or might not care about the evaluation order, but that is irrelevant. And Emacs Lisp is not exceptional in any way in this regard. – Drew Dec 04 '15 at 02:54
  • Just a note of support forDrew.The macro link is news to me. It's simply to allow multiple forms in just about every use case I have seen. "macros" don't even appear on the radar. – RichieHH Dec 13 '20 at 02:13
17

The most important reason for progn is described in the first line of the progn documentation (emphasis added):

progn is a special form that causes each of its arguments to be evaluated in sequence and then returns the value of the last one.

Addendum:

Without progn, sequence is not guaranteed, especially if subsequent expressions are dependent on the side effects or return values of the previous expressions. progn enforces execution sequence the same as textual sequence. Helps to not confuse execution with parsing. This behavior goes back to the fundamentals of lisp control structures and functional programming. Here's an excerpt (emphasis added) from the lisp reference manual:

The built-in control structures are special forms since their subforms are not necessarily evaluated or not evaluated sequentially.

Does progn boost performance?

Parsing performance, no. Execution performance, no. At best it may equal but never magically boost performance.

When is progn used?

...most often inside an unwind-protect, and, or, or in the then-part of an if.

Emacs User
  • 5,553
  • 18
  • 48
  • I'm not sure why that's so important. Emacs always evaluates sequentially. –  Dec 03 '15 at 11:05
  • 2
    @lunaryorn see the updated answer. – Emacs User Dec 03 '15 at 15:30
  • I'm not sure whether I understand your edit. Naturally there are special forms with a different evaluation order (e.g. `if`), but the normal evaluation order (e.g. top-level forms, function bodies, etc.) is textual. Sure, to some degree that's an implicit `progn`, but that's usually not what you use `progn` for in your own code. –  Dec 03 '15 at 15:39
  • I think the Elisp manual node [`(elisp) Sequencing`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Sequencing.html) which you link says it all. – Basil May 17 '18 at 02:46
13

A better way to understand what progn is is by comparing it to the family: prog1 and prog2. The n or 1 or 2 part of the name stands for the statement from the list whose result you are interested in. In other words, progn will return the result of the last statement it contains, whereas prog1 will return the first, and similar for prog2.

Today this functionality seems a little awkward since we learn to either expect the program to return in the last statement, or to instruct it explicitly what to return. Thus prog1 and prog2 are very seldom used. However, if you think about it, it makes sense, and here is how:

Different programming languages use different strategies to describe their semantics. Lisp family used to be tightly tied to denotational semantics. Without going into much detail, this kind of semantics has particular difficulty with something we grew to know as "statements", which are not "expressions". Meanings of code are typically thought in terms of function combinations, while a "statement" which cannot be even described as a function (since it doesn't evaluate to anything) is thus difficult to deal with. However, since Lisp permits side-effects, sometimes a programmer would want to use an expression without using its value in a way that it doesn't affect the expression following it. And this is where progX family comes in.

In C-like languages this feature is sometimes known as sequence point (i.e. ; and , for example). progn is as essential to Lisp-like languages as ; is to C-like languages. It is a fundamental feature of the language one cannot easily replace. However, unlike in C-style languages, Lisp tends to build syntactical abstractions by completely hiding the syntax of the lower level. And this perhaps why you don't see progn used all that often, yet it is one of the important building blocks, when it comes to building higher level language abstractions (s.a. macros).

wvxvw
  • 11,222
  • 2
  • 30
  • 55