Subject: bug#8711: 24.0.50; binding _ to unused values with lexical-binding

From: Stefan Monnier <[email-masked]>
Date: Mon, 23 May 2011 16:29:01 -0300

> My problem is basically that I have a macro "destructure-case" that
> expands to destructuring-bind, e.g.:

> (destructure-case location
>   ((:error _) nil)) ; do nothing

> expands to

> (ecase (car location)
>   (:error (destructuring-bind (_) (cdr location)
>             (ignore _)
>             nil)))

> The macro inserts the (ignore _) to suppress the "value returned from
> (car --cl-rest--) is unused" warning.

It can insert (ignore nil) instead which should have the same effect but
without triggering the other warning with lexical-binding.

> I think that rewriting (let ((_ foo))) to (progn foo nil) is not quite
> right because that loses the information that the value that flows to
> the variable _ is intentionally ignored, but I guess that is somewhat
> hard to fix this.  (Maybe byte-optimize-letX could call
> byte-optimize-form-code-walker directly but instead of specifying that
> the form is evaluated "for-effect" somehow say that the value is
> "ignorable".)

I'm not completely satisfied with the "value returned from <foo> is
unused" indeed, but it's not clear exactly how to fix it (short of
always silencing it, which I'd rather not since it occasionally catches
errors).

> It's perhaps easier to teach destructuring-bind the _ convention so that
> it can produce more direct code.

Could be.  destructuring-bind generates some other minorly-problematic
code for the lexbind case.

> There is also a somewhat related problem with loop:

> ;; -*- lexical-binding: t -*-
> (defun foo (alist) (loop for (_key . value) in alist collect value))

> produces a "variable `_key' not left unused" warning.

I think the same problem happens with dotimes/dolist using the old
definition: the loop vars `key' and `value' are let-bound outside the
loop and then setq'd at each loop iteration (it's this setq that causes
them to be "not left unused").  This was OK for the dynamic scoping case
because let-binding is significantly more costly than setq, but it is
not right for the lexical scoping case where the cost of let is not
higher than `setq' and where the semantic is actually then wrong:
e.g. if you "collect (lambda () value)" the current code ends up
returning a list of functions that all return the last `value', rather
than a list of functions that each return one of the `values' in
the alist.

        Stefan