Below.

 

From: arthur miller Sent: Saturday, November 9, 2024 11:33 AM

>IMHO, this is a problem with all of the

>if/and/when/while-let[*] thingies. If someone

>uses them a lot then she probably knows what

>goes on, in what sequence.  But a priori it's

>not so clear.

 

Only while-let.

 

The lack of obvious behavior/meaning and clear doc is a problem with them in general, IMO.

 

In particular, it wouldn't hurt to show an example of what each can expand to, in terms of let[*] etc. We do that in the Elisp manual when introducing cond, for example:

 

For example: (if A B C)  (cond (A B) (t C))

 

(We could even usefully do it to show let* in terms of let.)

 

>This may just mean that the doc needs to take pains to be very clear, maybe even with examples or by showing a macro expansion explicitly.

> 

>Using catch/throw, let[*], and/if/when/while together is always _clearer_, IMO.  And it's often no more verbose.  

 

I don't think so.

 

(catch/throw aren't needed for some of the *-let constructs, of course.)

 

IMO, use of explicit let, for binding, and explicit if/when/etc. for control flow, is clear. And if you don't use the *-let thingies much, or are new to them, then the former are clearer. Hence the need for good doc for the *-let combination bind&control constructs, at a minimum.

 

As you say, the *-let constructs are just "shorthand". And not much shorter, typically. Shorthand, but mentally more complex. The complexity isn't visual, it's in their meanings/behaviors, i.e., mental.

 

I'm not against all combinations of binding constructs with control constructs. E.g., constructs such as dolist bind vars. I just don't see much mileage/clarity gain from the *-let thingies. YMMV. At a minimum, their doc should be made very clear.

 

(let ((var1 init1) ... (varN initN)

      (loop-invarant init-loop-invariant))

  ...

  (while loop-invariant ...)

 ...)

 

In this context you are leaking loop-invariant in the entire scope of enclosing let-form, whereas

 

(let ((var1 init1) ... (varN initN))

  ...

  (while ((loop-invariant init-loop-invariant))

    ...)

 ...)

 

limits 'loop-invariant' to the lexical environment of while loop.

 

What's your argument? That there's no need to bind a local var for init-loop-invariant? OK. How's that relevant here?

 

(And there's no *-let construct in either of those examples, so ... what are you really comparing/demonstrating?)

 

In any case, if you did need a local var and wanted to keep its scope within the while you'd just wrap the while with its own let - end of story:

 

(let ((var1 init1) ... (varN initN)

  ...

  (let ((loop-invarant init-loop-invariant)) (while loop-invariant ...))

 ...)

 

Using a separate let makes clear where you want/need a separate binding scope.

___

 

It's enough for someone to scan this mail thread, to see possible confusion over what while-let does and how/when/where it does what à QED.

 

E.g., suggestions such as this, to help clarify the meaning/behavior of a while-let, make clear that it isn't so clear on its own:

 

>I'd align such clauses like this:

> 

> (while-let ((  b)

>             (  (< b end))

>             (e (next-single-property-change

>                  (1+ b) 'erc--msg nil end)))

>   ...)

> 

>to emphasize that.

 

I'm not saying such intentional formatting wouldn't help; it could. But suggesting such formatting just underlines how unclear the while-let construct seems to be, a priori.

 

Again, maybe a doc improvement could help. Or a pointer to this thread, where the back-&-forth might unconfuse someone a bit... ;-)

 

Från: Drew Adams Skickat: den 9 november 2024 19:07

 

IMHO, this is a problem with all of the
if/and/when/while-let[*] thingies.  If someone
uses them a lot then she probably knows what
goes on, in what sequence.  But a priori it's
not so clear.

This may just mean that the doc needs to take
pains to be very clear, maybe even with examples
or by showing a macro expansion explicitly.

Using catch/throw, let[*], and/if/when/while
together is always _clearer_, IMO.  And it's
often no more verbose.  Witness all of the
discussion about <X>-let* versus <X>-let names
and this current discussion.  The name itself
doesn't clearly tell you what it does... which
is OK, but only if the doc tells you that
clearly.

I'm not saying no one should use, or Elisp
shouldn't provide, if/and/when/while-let[*]
thingies.  I'm just saying (1) I don't find
them helpful, personally (I don't use them),
and (more importantly) (2) if we provide them
then their doc needs to be very specific about
what _exactly_ they do, and when (if not also
how).