all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-08 19:23 ` Philip Kaludercic
@ 2024-11-09  3:30   ` arthur miller
  0 siblings, 0 replies; 17+ messages in thread
From: arthur miller @ 2024-11-09  3:30 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: emacs-devel@gnu.org

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

>> (progn
>>   (while-let ((run t))
>>     (message "Running")
>>     (setf run nil))
>>   (message "out of loop"))
>>
>> It ends in infinite recursion. setf/setq have no effect on the lexical variable.
>>
>> I tooka look, but I don't understand why is it necessary to build while-let  on
>> if-let. This simplified version did it for me:
>>
>> (defmacro while-let (spec &rest body)
>>   "Bind variables according to SPEC and conditionally evaluate BODY.
>> Evaluate each binding in turn, stopping if a binding value is nil.
>> If all bindings are non-nil, eval BODY and repeat.
>>
>> The variable list SPEC is the same as in `if-let*'."
>>   (declare (indent 1) (debug if-let))
>>   (let* ((bindings (if (and (consp spec) (symbolp (car spec)))
>>                            (list spec)
>>                          spec))
>>          (variables (mapcar #'car bindings)))
>>     `(let* ,bindings
>>        (while (and ,@variables)
>>          ,@body))))
>
>With `if-let*' or `while-let' you want to have a sequence of
>computations that are evaluated in order (either once for `if-let*' or
>for every iteration in the case of `while-let'), until at least one
>evaluates to nil.  All subsequent bindings shouldn't be evaluated, as
>would be the case with your version of the macro.

Aha, that sounds like you want to optimize the evaluation of bindings
*before* the body is run? I think you should first generate correct
code, than optimize. As it is now, the while-let ends up in an endless loop.
Setting the lexical variable have no effect at all (with lexical binding
on). Simple macroexpand shows why:

(catch 'done918
  (while t
    (let* ((run (and t t)))
      (if run (progn (message "running") (setq run nil)) (throw 'done918 nil)))))

Problem is your if-let*:

(catch 'done917
  (while t
    (if-let* ((run t)) (progn (message "running") (setf run nil))
      (throw 'done917 nil))))

Furthermore, considering what you wrote in the answer; your if-let
will not do what you think, and shortcut evaluation of bindings, it
will do exactly the same as what I do in while-let:

(while-let ((x 1)
            (run t))
            (message "running")
            (setf run nil))

=> (catch 'done923
  (while t
    (let* ((x (and t 1)) (run (and x t)))
      (if run (progn (message "running") (setq run nil)) (throw 'done923 nil)))))

As you see from the macro expansion, your if-let* has expanded
to a let* which also evaluates all of the bindings before it runs the program.

The problem/bug is in if-expression. It 'ands' next value with the previous
value and 't, instead of previous value and it itself (I think that was the idea).
 If you fix that, I think it could work in terms of correctness, but it wold still
 evaluate all of the bindings.

To illustrate it better, we can change while-let loop and add one extra variable:

(while-let ((run t)
            (x 1))
  (message "running")
  (setf run nil))

=> (catch 'done929
    (while t
      (let* ((run (and t t)) (x (and run 1)))
        (if x (progn (message "running") (setq run nil)) (throw 'done929 nil)))))

If you want to optimize evaluation of bindings, I think one way would be to
generate a cascading let bindings, one per each binding, do a test and throw
your 'done nil if binding evaluated to nil. Perhaps there is some other way too,
I don't know, that was just the first idea.

I am doing this from igc branch, but I don't think that should matter.

However, I wonder if/how the author has tested this? I don't see any tests i
subr-tests.el for if-let, when-let and while-let. Not trying to be rude or
impolite, just an observation; I was doing simple comparison with a different
syntax for let-forms, and discovered that on the first try with a simplest example.

I suggest to do the trivial implementation of if-let, when-let and while-let
as shown in my first example until you get the optimized version. And you can
even have ordinary and star-versions of each form trivially. Just a suggestion of
course.

best regards
/arthur

________________________________
Från: Philip Kaludercic <philipk@posteo.net>
Skickat: den 8 november 2024 20:23
Till: arthur miller <arthur.miller@live.com>
Kopia: emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

arthur miller <arthur.miller@live.com> writes:

> (progn
>   (while-let ((run t))
>     (message "Running")
>     (setf run nil))
>   (message "out of loop"))
>
> It ends in infinite recursion. setf/setq have no effect on the lexical variable.
>
> I tooka look, but I don't understand why is it necessary to build while-let  on
> if-let. This simplified version did it for me:
>
> (defmacro while-let (spec &rest body)
>   "Bind variables according to SPEC and conditionally evaluate BODY.
> Evaluate each binding in turn, stopping if a binding value is nil.
> If all bindings are non-nil, eval BODY and repeat.
>
> The variable list SPEC is the same as in `if-let*'."
>   (declare (indent 1) (debug if-let))
>   (let* ((bindings (if (and (consp spec) (symbolp (car spec)))
>                            (list spec)
>                          spec))
>          (variables (mapcar #'car bindings)))
>     `(let* ,bindings
>        (while (and ,@variables)
>          ,@body))))

With `if-let*' or `while-let' you want to have a sequence of
computations that are evaluated in order (either once for `if-let*' or
for every iteration in the case of `while-let'), until at least one
evaluates to nil.  All subsequent bindings shouldn't be evaluated, as
would be the case with your version of the macro.

> (progn
>   (while-let ((run t))
>     (message "Running")
>     (setf run nil))
>   (message "out of loop"))  => "out of loop"
>
> Or did I missunderstood how to use while-let in subr.el?

--
        Philip Kaludercic on siskin

[-- Attachment #2: Type: text/html, Size: 19912 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-09  9:29 ` Yuri Khan
@ 2024-11-09 13:03   ` arthur miller
  2024-11-09 13:15     ` Yuri Khan
  0 siblings, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-09 13:03 UTC (permalink / raw)
  To: Yuri Khan; +Cc: emacs-devel@gnu.org

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

>> (progn
>>   (while-let ((run t))
>>     (message "Running")
>>     (setf run nil))
>>   (message "out of loop"))
>>
>> It ends in infinite recursion. setf/setq have no effect on the lexical variable.
>
>Probably not infinite recursion but infinite loop.
>
>Why would you expect anything else? ‘while-let’ is documented as:
>
>    Bind variables according to SPEC and conditionally evaluate BODY.

What should I expect?

It does not says *read-only bindings*, it says bindings. Is it
unreasonable to store a value in an established lexical binding?

(progn
  (let ((run t))
    (while run
      (message "running")
      (setf run nil))
    (message "not running")))

That is what I expect while-let to be equivalent to. But in practice
introduced bindings are "read only" since the current implementation of
while-let throws out bindings on each iteration of while loop, which
results in bindings being reset.

If that was the intention, I think it is counterintuitive, but I doubt it is.

[-- Attachment #2: Type: text/html, Size: 4876 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-09 13:15     ` Yuri Khan
@ 2024-11-09 13:38       ` arthur miller
  2024-11-09 13:41         ` Yuri Khan
  0 siblings, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-09 13:38 UTC (permalink / raw)
  To: Yuri Khan; +Cc: emacs-devel@gnu.org

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

>> >> (progn
>> >>   (while-let ((run t))
>> >>     (message "Running")
>> >>     (setf run nil))
>> >>   (message "out of loop"))
>> >>
>> >> It ends in infinite recursion. setf/setq have no effect on the lexical variable.
>> >
>> >Probably not infinite recursion but infinite loop.
>> >
>> >Why would you expect anything else? ‘while-let’ is documented as:
>> >
>> >    Bind variables according to SPEC and conditionally evaluate BODY.
>>
>> What should I expect?
>>
>> It does not says *read-only bindings*, it says bindings. Is it
>> unreasonable to store a value in an established lexical binding?
>
>I expect the binding is writable *but* it gets re-assigned on each iteration.

Yes.

>> That is what I expect while-let to be equivalent to.
>
>This is what I expect:
>
>    (progn
>      (let ((run))
>        (while (setf run t)
>          (message "running")
>          (setf run nil)       ; useless because ‘run’ will be
>reassigned right next
>        )
>      (message "not running")  ; unreachable
>    )
>

Mnjah; more like this:

(catch 'done
  (while t
    (let* ((run nil))
      (if run
          (do-body)
          (throw 'done nil)))))

I have already posted the macro expansions in respone to Phillip.
It is quite clear what is going on. I think it is a bug, or at
least very unintuitive behaviour. But the worst, we can see that the
claimed optimizaiton does not take place at all:

(pp (macroexpand-all
     '(while-let ((run t)
                  (x 'expensive)
                  (y 'more-expensive)
                  (z 'the-most-expensive))
        (message "running")
        (setf run nil))))

(catch 'done1522
  (while t
    (let*
        ((run (and t t)) (x (and run 'expensive)) (y (and x 'more-expensive))
         (z (and y 'the-most-expensive)))
      (if z (progn (message "running") (setq run nil)) (throw 'done1522 nil)))))

Which makes wonder if the convoluted code in subr.el is worth compared to the
naive implementation I posted. Perhaps someone can pull off the optimization with
 some clever macro, I don't know.

I think it was enough from me as an outsider to point out the possible bug. Whether
 people here wants to poop on it, or acknowledge and fix the bug is not up to me.

In other words, I think I am done here.

/best regards
________________________________
Från: Yuri Khan <yuri.v.khan@gmail.com>
Skickat: den 9 november 2024 14:15
Till: arthur miller <arthur.miller@live.com>
Kopia: emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

On Sat, 9 Nov 2024 at 20:03, arthur miller <arthur.miller@live.com> wrote:
>
> >> (progn
> >>   (while-let ((run t))
> >>     (message "Running")
> >>     (setf run nil))
> >>   (message "out of loop"))
> >>
> >> It ends in infinite recursion. setf/setq have no effect on the lexical variable.
> >
> >Probably not infinite recursion but infinite loop.
> >
> >Why would you expect anything else? ‘while-let’ is documented as:
> >
> >    Bind variables according to SPEC and conditionally evaluate BODY.
>
> What should I expect?
>
> It does not says *read-only bindings*, it says bindings. Is it
> unreasonable to store a value in an established lexical binding?

I expect the binding is writable *but* it gets re-assigned on each iteration.

> (progn
>   (let ((run t))
>     (while run
>       (message "running")
>       (setf run nil))
>     (message "not running")))
>
> That is what I expect while-let to be equivalent to.

This is what I expect:

    (progn
      (let ((run))
        (while (setf run t)
          (message "running")
          (setf run nil)       ; useless because ‘run’ will be
reassigned right next
        )
      (message "not running")  ; unreachable
    )

[-- Attachment #2: Type: text/html, Size: 14580 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-09 13:41         ` Yuri Khan
@ 2024-11-09 13:47           ` arthur miller
  2024-11-09 14:04             ` Yuri Khan
  2024-11-09 21:47             ` Joost Kremers
  0 siblings, 2 replies; 17+ messages in thread
From: arthur miller @ 2024-11-09 13:47 UTC (permalink / raw)
  To: Yuri Khan; +Cc: emacs-devel@gnu.org

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

>> least very unintuitive behaviour.
>
>Why? Pretty much all implementations of the ‘while’ loop in all
>languages I’ve seen re-evaluate the condition on every iteration.

That wasn't the un-intuitive part :-).

If it wasn't clear, the unintuitive part is that while-let was to
establish the local environment, so that we don't need to type:

(let ((som-var (init-form)))
    (while some-var
        ... ))

At least is how I understand the purpose of if-let, when-let and while-let.
________________________________
Från: Yuri Khan <yuri.v.khan@gmail.com>
Skickat: den 9 november 2024 14:41
Till: arthur miller <arthur.miller@live.com>
Kopia: emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

On Sat, 9 Nov 2024 at 20:38, arthur miller <arthur.miller@live.com> wrote:

> >I expect the binding is writable *but* it gets re-assigned on each iteration.
>
> Yes.
> I have already posted the macro expansions in respone to Phillip.
> It is quite clear what is going on. I think it is a bug, or at
> least very unintuitive behaviour.

Why? Pretty much all implementations of the ‘while’ loop in all
languages I’ve seen re-evaluate the condition on every iteration.

[-- Attachment #2: Type: text/html, Size: 3612 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-09 14:04             ` Yuri Khan
@ 2024-11-09 14:44               ` arthur miller
  2024-11-09 16:33               ` Alfred M. Szmidt
  1 sibling, 0 replies; 17+ messages in thread
From: arthur miller @ 2024-11-09 14:44 UTC (permalink / raw)
  To: Yuri Khan; +Cc: emacs-devel@gnu.org

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

>But if it did it that way, the condition (init-form) would only be
>evaluated once, and I’d find *that* counterintuitive. Consider the

?

I don't know man. Why would it be so? Loops conditions should always be
evaluated in a loop, otherwise how should loop terminate? But I don't
expect a loop to re-initiate all bindings from defaults each time it
runs an iteration. It is both expensive, unnecessary and counterintuitive.
Don't you think?

>usual form of a while loop:
>
>    (while-let ((run (some-condition)))
>      (message "running"))
>
>Do you expect that to evaluate (some-condition) once, then, if it’s
>initially true, run forever?

That usual form of while loop works because (some-condition) is a function,
and it obviously computes its condition based on the external environment.

Perhaps you can set some global value in the loop to stop the evaluation, or
perhaps (some-condition) computes the terminating condition based on some
other volatile values from the environment. I don't see is that in the
conflict to what I say.

If you instead write

(while-let ((run some-condition))
   (message "running"))

Than yes, the loop will not terminate unless you terminate it from the loop.
However, since we are throwing away the bindings on each iteration, we are
also throwing away the previously computed binding, we can't write:

(while-let ((run some-condition))
   (message "running")
   (setf run nil))

Which to me seems counterintuitive.
________________________________
Från: Yuri Khan <yuri.v.khan@gmail.com>
Skickat: den 9 november 2024 15:04
Till: arthur miller <arthur.miller@live.com>
Kopia: emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

On Sat, 9 Nov 2024 at 20:47, arthur miller <arthur.miller@live.com> wrote:

> If it wasn't clear, the unintuitive part is that while-let was to
> establish the local environment, so that we don't need to type:
>
> (let ((som-var (init-form)))
>     (while some-var
>         ... ))

But if it did it that way, the condition (init-form) would only be
evaluated once, and I’d find *that* counterintuitive. Consider the
usual form of a while loop:

    (while-let ((run (some-condition)))
      (message "running"))

Do you expect that to evaluate (some-condition) once, then, if it’s
initially true, run forever?

[-- Attachment #2: Type: text/html, Size: 7708 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-09 16:33               ` Alfred M. Szmidt
@ 2024-11-09 20:29                 ` arthur miller
  2024-11-10  6:22                   ` Eli Zaretskii
  0 siblings, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-09 20:29 UTC (permalink / raw)
  To: Alfred M. Szmidt, Yuri Khan; +Cc: emacs-devel@gnu.org

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

>> From: "Alfred M. Szmidt" <ams@gnu.org>
>> Cc: arthur.miller@live.com, emacs-devel@gnu.org
>> Date: Sat, 09 Nov 2024 11:33:45 -0500
>>
>>        (while-let ((run (some-condition)))
>>         (message "running"))
>>
>>    Do you expect that to evaluate (some-condition) once, then, if it’s
>>    initially true, run forever?
>>
>> That is how it is described in the manual, so yes (some-condition)
>> should only be done once, and not every iteration.  See (elisp)
>> Conditionals .
>
>Which could mean that the manual is wrong and needs to be fixed.
>The above description actually supports what Yuri was saying, not what
>Arthur and you expect.

Mnjah; if you consider this scatchy C:

{
  int foo = ..;
   ...
  for (int i=0, j=0; u < 10i++ )
  {
        do something with i, j
        .....
        do something with foo
  }

  i,j are not visible here
  ...
}

In other words, there might be variables live outisde of
the loop-scope we wish to access in the loop, and that is
what Yuri's example shows. However, i,j are not re-initiated
on each iteration, but remembers their value. The effecto of
while-let in current implementation is that i,j are re-initiated
in each iteration, not re-evaluated, if that makes it clear.

I am not sure how to illustrate in a better way. The net effect is
that lexical variables declared in while-let loop are "read-only".

They are not, but since they are re-iniated, it is pointless to
write to them.

Of course, all loop predicates should be evaled on each iteration,
but not re-iniated on each iteration. If that makes sense. Sorry,
I am not very good at writing.

When I see at my own KISS version, I see also it only initiates
variable, but does not re-evaluate function calls on each iteration;
I didn't really udnerstand it from the beginning, so this discussion
has cleared my mind a bit too.

However I am not sure exact how to fix it. But I believe a loop
where we can't update loop invariantes is a bit strange too.
________________________________
Från: Alfred M. Szmidt <ams@gnu.org>
Skickat: den 9 november 2024 17:33
Till: Yuri Khan <yuri.v.khan@gmail.com>
Kopia: arthur.miller@live.com <arthur.miller@live.com>; emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

   > If it wasn't clear, the unintuitive part is that while-let was to
   > establish the local environment, so that we don't need to type:
   >
   > (let ((som-var (init-form)))
   >     (while some-var
   >         ... ))

   But if it did it that way, the condition (init-form) would only be
   evaluated once, and I’d find *that* counterintuitive. Consider the
   usual form of a while loop:

       (while-let ((run (some-condition)))
         (message "running"))

   Do you expect that to evaluate (some-condition) once, then, if it’s
   initially true, run forever?

That is how it is described in the manual, so yes (some-condition)
should only be done once, and not every iteration.  See (elisp)
Conditionals .

      It can be convenient to bind variables in conjunction with using a
   conditional.  It's often the case that you compute a value, and then
   want to do something with that value if it's non-‘nil’.  The
   straightforward way to do that is to just write, for instance:

        (let ((result1 (do-computation)))
          (when result1
            (let ((result2 (do-more result1)))
              (when result2
                (do-something result2)))))

      Since this is a very common pattern, Emacs provides a number of
   macros to make this easier and more readable.  The above can be written
   the following way instead:

... following the various with various FOO-let forms, ending with
while-let.

[-- Attachment #2: Type: text/html, Size: 11694 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-09 13:47           ` Sv: " arthur miller
  2024-11-09 14:04             ` Yuri Khan
@ 2024-11-09 21:47             ` Joost Kremers
  1 sibling, 0 replies; 17+ messages in thread
From: Joost Kremers @ 2024-11-09 21:47 UTC (permalink / raw)
  To: arthur miller; +Cc: Yuri Khan, emacs-devel@gnu.org

On Sat, Nov 09 2024, arthur miller wrote:
> If it wasn't clear, the unintuitive part is that while-let was to
> establish the local environment, so that we don't need to type:
>
> (let ((som-var (init-form)))
>     (while some-var
>         ... ))
>
> At least is how I understand the purpose of if-let, when-let and while-let.

Yes, but for `while`, the pattern isn't complete. The `setq` inside the
loop is a crucial part:

```
(let ((a (foo ...)))
  (while a
    (do-stuff-with a)
    (setq a (foo ...))))
```

So the idea is that you want to test the result of some expression on each
iteration. `while-let` basically lets you type that expression only once,
instead of twice.

At least that's how I understand `while-let`.


-- 
Joost Kremers
Life has its moments



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-10  6:22                   ` Eli Zaretskii
  2024-11-10 10:40                     ` Joost Kremers
@ 2024-11-10 18:18                     ` arthur miller
  2024-11-11  5:13                       ` Yuri Khan
  1 sibling, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-10 18:18 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: ams@gnu.org, yuri.v.khan@gmail.com, emacs-devel@gnu.org

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

>> From: arthur miller <arthur.miller@live.com>
>> CC: "emacs-devel@gnu.org" <emacs-devel@gnu.org>
>> Date: Sat, 9 Nov 2024 20:29:29 +0000
>>
>> In other words, there might be variables live outisde of
>> the loop-scope we wish to access in the loop, and that is
>> what Yuri's example shows. However, i,j are not re-initiated
>> on each iteration, but remembers their value. The effecto of
>> while-let in current implementation is that i,j are re-initiated
>> in each iteration, not re-evaluated, if that makes it clear.
>>
>> I am not sure how to illustrate in a better way. The net effect is
>> that lexical variables declared in while-let loop are "read-only".
>>
>> They are not, but since they are re-iniated, it is pointless to
>> write to them.
>
>You can write to them indirectly, if the evaluation is properly
>written.  If the evaluation is just assigning a fixed value to a
>variable, then yes, writing to that variable in the body is pointless;
>but then so is the use of while-let, IMO.

That depends how you define the while-let semantics of course.

>Even in your for-loop example from C, the CONDITION part of the loop
>is re-evaluated on each iteration, and if you assign some fixed value
>to the loop control variables there, your loop might become an
>infloop, regardless of what you do in the body with those variables.

Infloops are not in question here, since they are results of a programmers
misstake. The job of for-loop in C or while-let in Emacs is not to ensure
always terminating loop.

>That's basically what the example of while-let you show at the
>beginning of this discussion did.

As I understand it now, Emacs while-loop is a unique kind of loop, at least
I have never seen a construction with such semantic before. The semantic
of while-let in Emacs is that of for-loop or while-loop in C++, but where
initialization of loop variables happens on each iteration

    for (int i=0; i<some_bound(); i++) {
        we can read i here, but
        we can't write to it
    }

Since re-initialization is happening on each iteration, as you say we have
to go via a third variable (or a function), and the variable must not be shadowed
by the local binding established by while-let spec. That does make while-let
pointless to use for not so unusual idiom in other languages:

(let ((run t))
  (while run
     ...
     (when (some-condition)
       (setf run nil))))

I personally would expect to be able to write:

(while-let ((run t))
  ...
  (when (some-condition)
  (setf run nil)))

Since while-let was supposed to simplify that case, but that wont work :).

So obviously I did missunderstood how while-let works, but I would say the
semantics are bit arcane. I haven't seen any other language with read-only
semantic for loop variables.

Somebody said in another mail that bindings are conditions. I think it is a
good illustration of while-let bindings, but it perhaps does not catch the
fact that they are not used as ordinary lexical bindings strongly enough, so,
perhaps a mention about not being settable from the loop is in order?

That would also be my answer for the question in another mail about what
to add to docs. Also perhaps mention that the way out of that loop is to either
go via an implicit variable, or to use try/catch or cl-block/cl-return-from to
break out of the loop.

As a remark:

Perhaps while-let is a wrong name for this construct to start with. It behaves
more like for-loops, but with a twist. Typically in C/C++ and derivatives, we
can't introduce a variable in while condition: while (int i = some_var ) is not
legal.

Since those bindings are not settable in loop body; they really are conditions,
perhaps while* is a better name for this construct, since it introduces
multiple conditions. But it is not good either, since this construct is really
somewhere in-between a while and for loop from other languages.





________________________________
Från: Eli Zaretskii <eliz@gnu.org>
Skickat: den 10 november 2024 07:22
Till: arthur miller <arthur.miller@live.com>
Kopia: ams@gnu.org <ams@gnu.org>; yuri.v.khan@gmail.com <yuri.v.khan@gmail.com>; emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

> From: arthur miller <arthur.miller@live.com>
> CC: "emacs-devel@gnu.org" <emacs-devel@gnu.org>
> Date: Sat, 9 Nov 2024 20:29:29 +0000
>
> In other words, there might be variables live outisde of
> the loop-scope we wish to access in the loop, and that is
> what Yuri's example shows. However, i,j are not re-initiated
> on each iteration, but remembers their value. The effecto of
> while-let in current implementation is that i,j are re-initiated
> in each iteration, not re-evaluated, if that makes it clear.
>
> I am not sure how to illustrate in a better way. The net effect is
> that lexical variables declared in while-let loop are "read-only".
>
> They are not, but since they are re-iniated, it is pointless to
> write to them.

You can write to them indirectly, if the evaluation is properly
written.  If the evaluation is just assigning a fixed value to a
variable, then yes, writing to that variable in the body is pointless;
but then so is the use of while-let, IMO.

Even in your for-loop example from C, the CONDITION part of the loop
is re-evaluated on each iteration, and if you assign some fixed value
to the loop control variables there, your loop might become an
infloop, regardless of what you do in the body with those variables.
That's basically what the example of while-let you show at the
beginning of this discussion did.

> Of course, all loop predicates should be evaled on each iteration,
> but not re-iniated on each iteration. If that makes sense. Sorry,
> I am not very good at writing.

If while-let doesn't seem to do the job in some code of yours, then
don't use it there.  Use something else.  AFAIU, while-let was
introduced for those cases where its use makes sense and does the job
cleaner and clearer than the alternatives.  It could be abused, of
course, but that's not necessarily its fault, is it?

Anyway, to get this long discussion back on track: is there a need to
clarify something in the documentation of while-let? if so, what?

[-- Attachment #2: Type: text/html, Size: 18472 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-10 12:10                       ` Alfred M. Szmidt
@ 2024-11-10 19:49                         ` arthur miller
  0 siblings, 0 replies; 17+ messages in thread
From: arthur miller @ 2024-11-10 19:49 UTC (permalink / raw)
  To: Alfred M. Szmidt, Joost Kremers
  Cc: eliz@gnu.org, yuri.v.khan@gmail.com, emacs-devel@gnu.org

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

>   @defmac while-let spec then-forms...
>   Like @code{when-let*}, but repeat until a binding in @var{spec} is
>   @code{nil}.  The return value is always @code{nil}.
>
>The "Like FOO" is confusing -- it is not like when-let*, when-let* is
>also not like let*.  E.g., when spec is (binding value) or just
>(value) (!?) -- which should be mentioned in the manual.
>
>These foo-LET are are mixing up the condition being tested and the
>binding, when there is no binding the form seems to be just a test as
>if you'd pass it directly to WHEN (or whatever).  There should be some
>example that SPEC is not at all like in LET, and that:
>
>(when-let* ((result1 (do-computation))
>            (        (do-more result1)))
>  (do-something result1))
>
>is something like (I guess?):
>
>(let ((result1 (do-computation)))
>  (when result1
>    (when (do-more result1)
>      (do-something result2))))
>
>And these mentions of "Like LET*" should be removed entierly.
>
>But this is a better, and a good start.
>
>   @code{while-let} replaces a common pattern in which a binding is
>   established outside the @{while}-loop, tested as part of the condition of
>   @{while} and subsequently changed inside the loop using the same expression
>   that it was originally bound to:
>
>   @example
>   (let ((result (do-computation)))
>     (while result
>       (do-stuff-with result)
>       (setq result (do-computation))))
>   @end example
>
>   Using @code{while-let}, this can be written more succinctly as:
>
>   @example
>   (while-let ((result (do-computation)))
>     (do-stuff-with result))
>   @end example
>
>   The binding of @code{result} is reestablished at every iteration, therefore
>   setting the value of @code{result} inside the loop has no effect. In order
>   to end the loop, @code{(do-computation)} should eventually return
>   @code{nil}.
>
>   This example uses a single binding for clarity, but obviously
>   @code{while-let} can establish multiple bindings. The loop runs as long as
>   all bindings are non-@code{nil}.
>   @end defmac
>   ```
>
>   Am I mistaken or is `while-let` a bit like a do..until loop that some
>   languages offer?

Isn't it also like named-let? But without the ability to call itself recursivey.
I haven't tried it yet, but seems like while-let is a special case of named-let,
an "anonymous named-let" with conditions passed as-they-are. In other words we could
generate while-let as named-let with gensym as the name? (if cl-lib was allowed in
subr.el so to say). I am not sure if I have done it correctly, probably not, but here
is a try:

(defmacro while-test (spec &rest body)
  (declare (indent defun))
  (let* ((name (gensym "while-let-"))
         (bindings (if (and (consp spec) (symbolp (car spec)))
                       (list spec)
                     spec)))
    `(named-let ,name ,spec
       ,@body
       (if (not (and ,@(mapcar #'car bindings)))
           nil
           (,name ,@(mapcar #'cadr bindings))))))
________________________________
Från: Alfred M. Szmidt <ams@gnu.org>
Skickat: den 10 november 2024 13:10
Till: Joost Kremers <joostkremers@fastmail.fm>
Kopia: eliz@gnu.org <eliz@gnu.org>; arthur.miller@live.com <arthur.miller@live.com>; yuri.v.khan@gmail.com <yuri.v.khan@gmail.com>; emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?

   @defmac while-let spec then-forms...
   Like @code{when-let*}, but repeat until a binding in @var{spec} is
   @code{nil}.  The return value is always @code{nil}.

The "Like FOO" is confusing -- it is not like when-let*, when-let* is
also not like let*.  E.g., when spec is (binding value) or just
(value) (!?) -- which should be mentioned in the manual.

These foo-LET are are mixing up the condition being tested and the
binding, when there is no binding the form seems to be just a test as
if you'd pass it directly to WHEN (or whatever).  There should be some
example that SPEC is not at all like in LET, and that:

(when-let* ((result1 (do-computation))
            (        (do-more result1)))
  (do-something result1))

is something like (I guess?):

(let ((result1 (do-computation)))
  (when result1
    (when (do-more result1)
      (do-something result2))))

And these mentions of "Like LET*" should be removed entierly.

But this is a better, and a good start.

   @code{while-let} replaces a common pattern in which a binding is
   established outside the @{while}-loop, tested as part of the condition of
   @{while} and subsequently changed inside the loop using the same expression
   that it was originally bound to:

   @example
   (let ((result (do-computation)))
     (while result
       (do-stuff-with result)
       (setq result (do-computation))))
   @end example

   Using @code{while-let}, this can be written more succinctly as:

   @example
   (while-let ((result (do-computation)))
     (do-stuff-with result))
   @end example

   The binding of @code{result} is reestablished at every iteration, therefore
   setting the value of @code{result} inside the loop has no effect. In order
   to end the loop, @code{(do-computation)} should eventually return
   @code{nil}.

   This example uses a single binding for clarity, but obviously
   @code{while-let} can establish multiple bindings. The loop runs as long as
   all bindings are non-@code{nil}.
   @end defmac
   ```

   Am I mistaken or is `while-let` a bit like a do..until loop that some
   languages offer?


   --
   Joost Kremers
   Life has its moments



[-- Attachment #2: Type: text/html, Size: 16150 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-11  5:13                       ` Yuri Khan
@ 2024-11-11  8:49                         ` arthur miller
  2024-11-11 12:23                           ` tomas
  0 siblings, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-11  8:49 UTC (permalink / raw)
  To: Yuri Khan; +Cc: Eli Zaretskii, ams@gnu.org, emacs-devel@gnu.org

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

>Comprarison with a for loop is somewhat strained here. The while-let

I didn't meant to say that while-let was equivalent to that for-loop;
but tried to illustrate the expectaions. I hope it was clear from the rest.

>loop in Elisp is directly analogous to this C++ while loop:
>
>    #include <iostream>
>
>    int main() {
>        while (bool run = true) {
>            std::cout << "running\n";
>            run = false;
>        }
>        std::cout << "out of loop\n";
>    }
>
>and yes, it’s an infloop, too.

Actually didn't know we can introduce new variable in while declaration in
C++; in C it is verbotten:

~/repos/test $ gcc -o test test.c
test.c: In function 'main':
test.c:3:10: error: expected expression before 'int'
    3 |   while (int i = 0) {
      |          ^~~
test.c:4:5: error: 'i' undeclared (first use in this function)
    4 |     i++;
      |     ^
test.c:4:5: note: each undeclared identifier is reported only once for each function it appears in

But that is just a regression (thought it as in C++ too :-)).

>What you’re looking for, though, seems to be a while loop with a
>break, which is expressed as a catch/throw in Elisp.

Yes, that is what I came to as well, if you check the rest of the
response to Eli as I suggested to mention catch/throw or cl-block/cl-return-from
in the docs.

Even better is named-let, which seems to be a general
version of while-let:

(defmacro while-test (spec &rest body)
  (declare (indent defun))
  (let* ((name (gensym "while-let-"))
         (bindings (if (and (consp spec) (symbolp (car spec)))
                       (list spec)
                     spec)))
    `(named-let ,name ,spec
       ,@body
       (if (not (and ,@(mapcar #'car bindings)))
           nil
         (,name ,@(mapcar #'cadr bindings))))))

(pp (macroexpand-1
     '(while-test ((run t))
        (setf run nil))) (current-buffer))

(named-let while-let-141 ((run t))
  (setf run nil) (if (not (and run)) nil (while-let-141 t)))

(pp (macroexpand-1
     '(while-let ((run t))
        (setf run nil))) (current-buffer))

(catch 'done140
  (while t (if-let* ((run t)) (progn (setf run nil)) (throw 'done140 nil))))

As seen, they both expand to equivalent infinite loop.

For the illustration, named-let expands to a nice while loop itself:

(pp (macroexpand-all
     '(while-test ((run t))
        (setf run nil))) (current-buffer))

(let ((run t))
  (let (retval)
    (while
        (let ((run run))
          (progn
            (setq run nil)
            (if (not (and run)) nil (progn (setq run t) :recurse)))))
    retval))

In my personal opinion while-let, while meant to be a "shortcut" to
certain style of expressions is a bit unfortunate name, since the "-let"
part of the name suggest establishing an environment around the body,
however that environment is read only which is not normal semantic of
let-bindings.  In other words, the devil is in the details which perhaps was
 not intentional?

[-- Attachment #2: Type: text/html, Size: 14124 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-11  8:49                         ` Sv: " arthur miller
@ 2024-11-11 12:23                           ` tomas
  0 siblings, 0 replies; 17+ messages in thread
From: tomas @ 2024-11-11 12:23 UTC (permalink / raw)
  To: arthur miller; +Cc: emacs-devel@gnu.org

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

On Mon, Nov 11, 2024 at 08:49:39AM +0000, arthur miller wrote:

[...]

> Actually didn't know we can introduce new variable in while declaration in
> C++; in C it is verbotten:
> 
> ~/repos/test $ gcc -o test test.c
> test.c: In function 'main':
> test.c:3:10: error: expected expression before 'int'
>     3 |   while (int i = 0) {
>       |          ^~~
> test.c:4:5: error: 'i' undeclared (first use in this function)
>     4 |     i++;
>       |     ^
> test.c:4:5: note: each undeclared identifier is reported only once for each function it appears in

AFAIK, it is erlaubt since C99.

Cheers
-- 
t

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Is this a bug in while-let or do I missunderstand it?
@ 2024-11-12  3:36 arthur miller
  2024-11-12  8:30 ` Joost Kremers
  0 siblings, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-12  3:36 UTC (permalink / raw)
  To: joostkremers@fastmail.fm; +Cc: emacs-devel@gnu.org

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

>+@code{while-let} replaces a pattern in which a binding is established
>+outside the @code{while}-loop, tested as part of the condition of
>+@code{while} and subsequently changed inside the loop using the same
>+expression that it was originally bound to:
>+
>+@example
>+(let ((result (do-computation)))
>+  (while result
>+    (do-stuff-with result)
>+    (setq result (do-computation))))
>+@end example
>+
>+Using @code{while-let}, this can be written more succinctly as:
>+
>+@example
>+(while-let ((result (do-computation)))
>+  (do-stuff-with result))
>+@end example
>+
>+One crucial difference here is the fact that in the first code example,
>+@code{result} is scoped outside the @code{wile} loop, whereas in the
>+second example, its scope is confined to the @code{while-let} loop.  As
>+a result, changing the value of @code{result} inside the loop has no
>+effect on the subsequent iteration.
>+@end defmac

The scope of the let-binding is the same in both. The crucial
difference is that in the first example, the user have control over
when and how 'result' is evaluated. The user can for example do:

(let ((result (do-computation)))
  (while result
    (do-stuff-with result)
    (setq result (do-some-other-computation))))

Whereas in the other example, the code is automatically generated
to pass in the original condition calculation, and the user can not
interfere with the computation of the condition.

[-- Attachment #2: Type: text/html, Size: 5976 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Is this a bug in while-let or do I missunderstand it?
  2024-11-12  3:36 Is this a bug in while-let or do I missunderstand it? arthur miller
@ 2024-11-12  8:30 ` Joost Kremers
  2024-11-12 17:55   ` Alfred M. Szmidt
  2024-11-12 23:08   ` arthur miller
  0 siblings, 2 replies; 17+ messages in thread
From: Joost Kremers @ 2024-11-12  8:30 UTC (permalink / raw)
  To: arthur miller; +Cc: emacs-devel@gnu.org

On Tue, Nov 12 2024, arthur miller wrote:
> The scope of the let-binding is the same in both.

I don't see how. With `while`, `result` is let-bound outside the loop, with
`while-let` it's bound inside the loop, even after macroexpanding it:

```
(macroexpand-all '(while-let ((result (foo)))
                    (bar result)))

==> 

(catch 'done15
  (while t
    (let*
        ((result
          (and t
               (foo))))
      (if result
          (progn
            (bar result))
        (throw 'done15 nil)))))
```

In fact, with `while`, you can use `result` even before you enter the loop:

```

(let ((result (do-something)))
  (do-something-with result)
  ...
  (while result
    (do-something-else-with result)
    (setq result (do-yet-another-thing))))
```

So clearly the scope of `result` is wider.

> The crucial
> difference is that in the first example, the user have control over
> when and how 'result' is evaluated. The user can for example do:
>
> (let ((result (do-computation)))
>   (while result
>     (do-stuff-with result)
>     (setq result (do-some-other-computation))))

Yes, and if that's what you need, you should use `while`.

> Whereas in the other example, the code is automatically generated
> to pass in the original condition calculation, and the user can not
> interfere with the computation of the condition.

Yes, but that's exactly the point of `while-let`. `while-let` is not there
to replace `while`, it's a different macro for a different (though related)
purpose.

Mind you, what you want to do can still be done with `while-let`, provided
you establish the relevant binding *outside* the loop:

```
(let ((continue t))
  (while-let ((a (foo))
              (b (bar))
              (  continue))
    (do-some-stuff)
    ...
    (when (stop-condition)
      (setq continue nil))))
```

I think I understand where your confusion is coming from, and I've tried to
address it in my proposed patch for the documentation. If you feel it's
still not clear enough, I'll happily take another look.

-- 
Joost Kremers
Life has its moments



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Is this a bug in while-let or do I missunderstand it?
  2024-11-12  8:30 ` Joost Kremers
@ 2024-11-12 17:55   ` Alfred M. Szmidt
  2024-11-12 23:21     ` Sv: " arthur miller
  2024-11-12 23:08   ` arthur miller
  1 sibling, 1 reply; 17+ messages in thread
From: Alfred M. Szmidt @ 2024-11-12 17:55 UTC (permalink / raw)
  To: Joost Kremers; +Cc: arthur.miller, emacs-devel

   > The scope of the let-binding is the same in both.

   I don't see how. With `while`, `result` is let-bound outside the loop, with
   `while-let` it's bound inside the loop, even after macroexpanding it:

And that is (again) the crux of the matter, one group thinks it is LET
bound outside of the loop, another inside.

Consider this, which will pass nil to BAR, but also reassign RESULT to
whatever FOO returns each iteration; which is the part that is
confusing for those who consider LET to be the binding and scope of
the variables (this also makes it much harder to debug code I think).

(while-let ((result (foo)))
  (setq result nil)
  (bar result))

Which expands to:
 
(catch 'done18
  (while t
    (let* ((result (and t (foo))))
      (if result
	  (progn
	    (setq result nil)
	    (bar result))
	(throw 'done18 nil)))))



   Mind you, what you want to do can still be done with `while-let`, provided
   you establish the relevant binding *outside* the loop:

Then what point is while-let?  Should there be a let-while? And a
let-while-let?  There are 20 occurences of while-let in Emacs ...



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-12  8:30 ` Joost Kremers
  2024-11-12 17:55   ` Alfred M. Szmidt
@ 2024-11-12 23:08   ` arthur miller
  1 sibling, 0 replies; 17+ messages in thread
From: arthur miller @ 2024-11-12 23:08 UTC (permalink / raw)
  To: Joost Kremers; +Cc: emacs-devel@gnu.org

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

>> The scope of the let-binding is the same in both.
>
>I don't see how. With `while`, `result` is let-bound outside the loop, with
>`while-let` it's bound inside the loop, even after macroexpanding it:
>
>```
>(macroexpand-all '(while-let ((result (foo)))
>                    (bar result)))
>
>==>
>
>(catch 'done15
>  (while t
>    (let*
>        ((result
>          (and t
>               (foo))))
>      (if result
>          (progn
>            (bar result))
>        (throw 'done15 nil)))))
>```
>
>In fact, with `while`, you can use `result` even before you enter the loop:
>
>```
>
>(let ((result (do-something)))
>  (do-something-with result)
>  ...
>  (while result
>    (do-something-else-with result)
>    (setq result (do-yet-another-thing))))
>```
>
>So clearly the scope of `result` is wider.

Indeed; I constantly forgett what while-let expands to. I had in mind
a let-over-while, but while-let does not expand to let-over-while, but
to a while.

>> The crucial
>> difference is that in the first example, the user have control over
>> when and how 'result' is evaluated. The user can for example do:
>>
>> (let ((result (do-computation)))
>>   (while result
>>     (do-stuff-with result)
>>     (setq result (do-some-other-computation))))
>
>Yes, and if that's what you need, you should use `while`.
>Yes, but that's exactly the point of `while-let`. `while-let` is not there
>to replace `while`, it's a different macro for a different (though related)
>purpose.

Yes. That was my conclusion too; it is its own construct. The name is perhaps
a misnomer.

>Mind you, what you want to do can still be done with `while-let`, provided
>you establish the relevant binding *outside* the loop:
>
>```
>(let ((continue t))
>  (while-let ((a (foo))
>              (b (bar))
>              (  continue))
>    (do-some-stuff)
>    ...
>    (when (stop-condition)
>      (setq continue nil))))
>```

Or named-let. Perhaps bindings in spec should be rather called "named conditions"
than let-bindings, because their nature is somewhat different from ordinary
let-condiitions.

>I think I understand where your confusion is coming from, and I've tried to
>address it in my proposed patch for the documentation. If you feel it's
>still not clear enough, I'll happily take another look

To ge honest, I just disslike "-let" part of the "while-let", because it
got me to think more of let, than of while. Can also be just me.

[-- Attachment #2: Type: text/html, Size: 12094 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-12 17:55   ` Alfred M. Szmidt
@ 2024-11-12 23:21     ` arthur miller
  2024-11-12 23:31       ` Joost Kremers
  0 siblings, 1 reply; 17+ messages in thread
From: arthur miller @ 2024-11-12 23:21 UTC (permalink / raw)
  To: Alfred M. Szmidt, Joost Kremers; +Cc: emacs-devel@gnu.org

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

>> The scope of the let-binding is the same in both.
>
>   I don't see how. With `while`, `result` is let-bound outside the loop, with
>   `while-let` it's bound inside the loop, even after macroexpanding it:
>
>And that is (again) the crux of the matter, one group thinks it is LET
>bound outside of the loop, another inside.

Yepp, you have put a finger on it.

It is not so strange we have two views. It is a let-over-while that expands
into while-over-let :-).

Since the expansion get evaled, I guess we should see it as a while-over-let.

The only confusing part is that we are illustrating it with let-over-while
example and sort-of saying it is a shortcut to let-over-while.


[-- Attachment #2: Type: text/html, Size: 3053 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Sv: Is this a bug in while-let or do I missunderstand it?
  2024-11-12 23:21     ` Sv: " arthur miller
@ 2024-11-12 23:31       ` Joost Kremers
  0 siblings, 0 replies; 17+ messages in thread
From: Joost Kremers @ 2024-11-12 23:31 UTC (permalink / raw)
  To: arthur miller; +Cc: Alfred M. Szmidt, emacs-devel@gnu.org

On Tue, Nov 12 2024, arthur miller wrote:
>>> The scope of the let-binding is the same in both.
>>
>>   I don't see how. With `while`, `result` is let-bound outside the loop, with
>>   `while-let` it's bound inside the loop, even after macroexpanding it:
>>
>>And that is (again) the crux of the matter, one group thinks it is LET
>>bound outside of the loop, another inside.
>
> Yepp, you have put a finger on it.
>
> It is not so strange we have two views. It is a let-over-while that expands
> into while-over-let :-).

It's not a let-over-while. The let-over-while snippet was just used to
explain why the macro was introduced, but (as you mention) it's misleading.
That's why in my first proposal for the documentation, I mentioned the
difference in scope explicitly. I've now taken that part out again, though,
and am trying to explain `while-let` on its own, without reference to
the `while` pattern it replaces.

-- 
Joost Kremers
Life has its moments



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2024-11-12 23:31 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-12  3:36 Is this a bug in while-let or do I missunderstand it? arthur miller
2024-11-12  8:30 ` Joost Kremers
2024-11-12 17:55   ` Alfred M. Szmidt
2024-11-12 23:21     ` Sv: " arthur miller
2024-11-12 23:31       ` Joost Kremers
2024-11-12 23:08   ` arthur miller
  -- strict thread matches above, loose matches on Subject: below --
2024-11-08 16:25 arthur miller
2024-11-08 19:23 ` Philip Kaludercic
2024-11-09  3:30   ` Sv: " arthur miller
2024-11-09  9:29 ` Yuri Khan
2024-11-09 13:03   ` Sv: " arthur miller
2024-11-09 13:15     ` Yuri Khan
2024-11-09 13:38       ` Sv: " arthur miller
2024-11-09 13:41         ` Yuri Khan
2024-11-09 13:47           ` Sv: " arthur miller
2024-11-09 14:04             ` Yuri Khan
2024-11-09 14:44               ` Sv: " arthur miller
2024-11-09 16:33               ` Alfred M. Szmidt
2024-11-09 20:29                 ` Sv: " arthur miller
2024-11-10  6:22                   ` Eli Zaretskii
2024-11-10 10:40                     ` Joost Kremers
2024-11-10 12:10                       ` Alfred M. Szmidt
2024-11-10 19:49                         ` Sv: " arthur miller
2024-11-10 18:18                     ` arthur miller
2024-11-11  5:13                       ` Yuri Khan
2024-11-11  8:49                         ` Sv: " arthur miller
2024-11-11 12:23                           ` tomas
2024-11-09 21:47             ` Joost Kremers

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.