all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: <tomas@tuxteam.de>
To: help-gnu-emacs@gnu.org
Subject: let, let*, oh, why [was: Elisp - Function returning a list]
Date: Wed, 16 Dec 2020 12:52:42 +0100	[thread overview]
Message-ID: <20201216115242.GB11162@tuxteam.de> (raw)
In-Reply-To: <trinity-b842f23a-7a23-4ec4-8101-101f8ff7730e-1608104163759@3c-app-mailcom-bs15>

[-- Attachment #1: Type: text/plain, Size: 4131 bytes --]

On Wed, Dec 16, 2020 at 08:36:03AM +0100, steve-humphreys@gmx.com wrote:
> > From: "Emanuel Berg via Users list for the GNU Emacs text editor" <help-gnu-emacs@gnu.org>

[...]

> > It is better to do all computation in the `let's, then use
> > them. No `setq' needed.

I generally agree, but not 100% (all generalizations suck, you know ;-)

> Example? Is there anything written about it?

What setq does is to "search upwards" from where it is until it
"finds the variable", and then sets its value as instructed.

If it doesn't find that variable, it creates a new one at the
"top level", to be able to accomplish this task.

I put "search upwards" and "find the variable" in quotes, because
they deserve some explanation. I'll limit myself here to the
"upwards" part:

What "upwards" means depends on whether you are under dynamic
scope (traditional) or lexical scope (more modern, recommended
almost always).

Under dynamic scope, the search for the variable goes up the call
chain: if the function where the setq is in "sees" that variable,
then it's there. Otherwise it asks its caller, and so on.

Under lexical scope, the search considers the source code: if
that variable is visible/defined in the current expression (think
"block", if you're coming from C/Perl/Python/PHP/Java), then that's
it. Otherwise go look in the enclosing expression.

Needless to say, this is the source of lots of fun: if you are
doing something in your code and import a snippet of code from
elsewhere (for the lexical case) or just call some code elsewhere,
and "they" trample on your "variables", spooky things happen.

In the dynamic case, those things are very spooky. Imagine
you have some code:

  (setq x 3)
  (setq y 4)

and call on Tomas's library to get the last mouse click coordinates.

  (setq mouse-x (car (tomas-coords)))

Jane's library does this (CAVEAT: there are nicer ways to do this,
apart from the "obvious" error that this function tramples over
whatever values mouse-pos, x, and y might have "globally".

I'm doing that to have a small working example. I repeat: DON'T DO
IT THIS WAY ;-)

  (defun tomas-coords ()
    (setq mouse-pos (mouse-position)) ; elisp manual 29.16
    ;; mouse-position has as first arg the frame. Let's get rid of that:
    (setq x (cadr mouse-pos))
    (setq y (cddr mouse-pos))
    (cons x y)) ;; return the pair (x . y)

Now your 'x' above isn't 3 anymore, but has some random value depending
on where your user was wiggling around the mouse. Oops.

Now under lexical scope things aren't so bleak, but still annoying.

That's why function arguments and let are there. They create a
kind of barrier for private variable names. A slightly better
version of the above function would then be:

  (defun tomas-coords ()
    (let ((mouse-pos (mouse-position))) ; elisp manual 29.16
      ;; mouse-position has as first arg the frame. Let's get rid of that:
      (let ((x (cadr mouse-pos))
            (y (cddr mouse-pos)))
        (cons x y)))) ;; return the pair (x . y)
      
So the `let' is telling elisp: "look, we are introducing here a
new variable called `x'. It has nothing to do with any other `x'
out/up there". Or "Any Similarity to Persons Living or Dead is
Purely Coincidental", as some like to put it. Still, the "here"
in the phrase above is interpreted differently depending on
whether we're "flying" dynamically or lexically.

Why the two nested `let's above, you ask? Well, in the variable-
assignment part of a let each arm is independent of the others.

The line above ...(y (cddr mouse-pos)) doesn't "see" the `x'
defined above it. It is as if all those parts were happening
at the same time. So for the `x' and `y' assignments to "see"
the just assigned `mouse-pos', we must `let' that happen
before.

That's why `let*' has been invented. Basically,

  (let* ((foo blah)
         (bar bleh)
         (baz mih))
    ...)

is equivalent, but arguably more readable than

  (let ((foo blah))
     (let ((bar bleh))
       (let ((baz mih))
         ...)))

HTH
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

  parent reply	other threads:[~2020-12-16 11:52 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-16  3:25 Elisp - Function returning a list steve-humphreys
2020-12-16  4:09 ` Jean Louis
2020-12-16  4:17   ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-16  5:04     ` steve-humphreys
2020-12-16  5:39       ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-16  7:36         ` steve-humphreys
2020-12-16  8:55           ` Joost Kremers
2020-12-16 10:25           ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-16 11:52           ` tomas [this message]
2020-12-16 14:13             ` let, let*, oh, why [was: Elisp - Function returning a list] Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-16 15:10               ` Jean Louis
2020-12-16 15:58                 ` Stefan Monnier
2020-12-16 18:37                   ` Jean Louis
2020-12-16 19:04                     ` Stefan Monnier
2020-12-16 20:05                       ` Jean Louis
2020-12-16 20:34                         ` tomas
2020-12-16 20:06                       ` tomas
2020-12-18 15:08                       ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-18 14:27                 ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-18 17:42                   ` Jean Louis
2020-12-18 20:57                     ` Eli Zaretskii
2020-12-20  4:49                     ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-20  5:06                       ` Thien-Thi Nguyen
2020-12-20  7:02                         ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-20  7:16                           ` Thien-Thi Nguyen
2020-12-21  2:34                             ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-20 13:38                           ` Jean Louis
2020-12-20  6:21                       ` Jean Louis
2020-12-20 23:20                       ` Drew Adams
2020-12-21  4:50                         ` Jean Louis
2020-12-21  5:40                           ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-21  9:17                             ` tomas
2020-12-21 15:20                               ` Drew Adams
2020-12-21 15:50                                 ` tomas
2020-12-25 14:41                       ` 황병희
2020-12-26  4:22                         ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-26  6:18                           ` Jean Louis
2020-12-26  6:33                             ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-26  7:07                               ` Christopher Dimech
2020-12-26  9:53                               ` Jean Louis
2020-12-26 10:11                                 ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-26  9:53                               ` Jean Louis
2020-12-26 10:20                                 ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-27  9:11                                   ` Byung-Hee HWANG
2020-12-27 11:52                                     ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-27 11:56                                       ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-26  6:44                           ` Byung-Hee HWANG
2020-12-16  4:30   ` Elisp - Function returning a list steve-humphreys
2020-12-16  4:38     ` Yuri Khan
2020-12-16  4:48       ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-16  5:20         ` steve-humphreys
2020-12-16  5:18       ` steve-humphreys
2020-12-16  5:33       ` Jean Louis
2020-12-16  5:42         ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-12-16  8:01           ` Elisp - Function returning a sequence of times Jean Louis
2020-12-16  9:05             ` steve-humphreys
2020-12-16  9:20               ` Joost Kremers
2020-12-16  9:40                 ` steve-humphreys
2020-12-16 21:54             ` Michael Heerdegen
2020-12-16  4:13 ` Elisp - Function returning a list Emanuel Berg via Users list for the GNU Emacs text editor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201216115242.GB11162@tuxteam.de \
    --to=tomas@tuxteam.de \
    --cc=help-gnu-emacs@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.