[Top][All Lists]

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

Re: Closures in Emacs and their usage scenarios.

From: Emanuel Berg
Subject: Re: Closures in Emacs and their usage scenarios.
Date: Thu, 30 Sep 2021 01:06:57 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Tomas Hlavaty wrote:

> In Emacs Lisp, closures mutating captured variables might be
> rare now because lexical scoping arrived recently.

Well, "[s]upport for lexical scoping in Emacs Lisp" came in
Emacs 24.1. I don't know if you can ask Emacs when something
came or when a particular version came, but that mail to
info-gnu-emacs is dated 2012-06-10, so that's not yesterday. [1]
It is 9y 3m 19d ago.

> There are examples in the Emacs code base already, see
> thunk-delay, for example.

It would help to see examples of the most base use cases.
One can always combine it into whatever level of complexity
one desires after that ...

> The toggle-counter-direction is an interesting example.

I don't understand what it is supposed to show?

> Next step could be showing the wonderful concept of
> generators; brilliantly shown, for example, in a solution of
> the same fringe problem. Once one understands this, it is
> a great way of creating light weight streams on the spot.
> It is also a robust solution to off-by-one errors often
> caused by complexities of indexing in complex loops.

Okay, can you show this? I mean the streams ...

> Because closures and dynamic binding does not go together
> well. Luckily, that is changing now and closures became
> relevant in ELisp.

Oh, no, not this again ... the counter example (not a pun), is
that an example of a "shared closure" (several defuns closing
it), with a "state" (what I called memory earlier) in the form
of the "captured variable" `times', and that variable is
"mutated" since it's value is altered with the `cl-incf',
`cl-decf' and `setq' setters, while in Haskell and OCaml -
which don't allow that - instead of changing the variable one
would instead have to add a new one, and that wouldn't work
here, since it is all based on operations targeted at
ONE variable?

Is that a correct interpretation of the terminology?

;;; -*- lexical-binding: t -*-
;;; this file:

(require 'cl-lib)

(let ((times))
  (defun times-incf (&optional x)
    (cl-incf times (or x 1)) )

  (defun times-decf (&optional x)
    (cl-decf times (or x 1)) )

  (defun times-reset (&optional x)
    (setq times (or x 0) ))

  (defun times-print ()
    (insert (number-to-string times)) ))

;; (times-reset)     ;    0
;; (times-reset 100) ;  100
;; (times-print)     ; "100"
;; (times-incf)      ;  101
;; (times-incf 10)   ;  111
;; (times-decf 111)  ;    0
;; (times-decf)      ;   -1

So here we see a theoretical use case, which is the OO design.

In practice, there are two use cases what I can see, one is
the state (the persistent variable between calls) and the
other is sharing data between functions.

Maybe you see something more, do tell ...

And, what other use cases are there? Again, keep examples as
simple as possible ...

>> Note also that such mutated+captured variables are more costly (at
>> least in the most prevalent way to implement closures).
> [...] In any case, optimizing this is not really a high
> priority issue I think.

Well, if someone wants to do it it doesn't really matter what
the priority is ... it's always like that BTW.


underground experts united

reply via email to

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