6

I have this function:

(defun uikit-autolayout (stackview)
  "Ask STACKVIEW to auto layout."
  (let* ((orientation-index (pcase (uikit--orientation-of stackview)
                              ('left 0) ; rotate clockwise 0 degree
                              ('bottom 1) ; rotate 90 degree
                              ('right 2) ; 180 degree
                              ('top 3))) ; 270 degree
         (last-left (byte-compile (lambda (SELF) (ignore SELF) (uikit-left-of stackview))))
         (space-func (pcase (uikit--autolayout-of stackview)
                       ('stacking (byte-compile (lambda () (uikit--stacking-space-of stackview))))
                       ('equal-spacing #'uikit-equal-spacing-space-of)))
         (top-func (pcase (uikit--v-align-of stackview)
                     ('top (lambda (SELF) (uikit-top-of (uikit--parent-stackview-of SELF))))
                     ('center (lambda (SELF)
                                (+ (uikit-top-of (uikit--parent-stackview-of SELF))
                                   (/ (- (uikit--max-subview-height (uikit--parent-stackview-of SELF))
                                         (uikit-content-height-of SELF)) 2))))
                     ('bottom (lambda (SELF)
                                (- (uikit-bottom-of (uikit--parent-stackview-of SELF))
                                   (uikit-content-width-of SELF)))))))
    (let ((uikit-left-of (nth orientation-index '(uikit-left-of uikit-bottom-of uikit-right-of uikit-top-of)))
          (uikit-bottom-of (nth orientation-index '(uikit-bottom-of uikit-right-of uikit-top-of uikit-left-of)))
          (uikit-right-of (nth orientation-index '(uikit-right-of uikit-top-of uikit-left-of uikit-bottom-of)))
          (uikit-top-of (nth orientation-index '(uikit-top-of uikit-left-of uikit-bottom-of uikit-right-of))))
      ;; ??? unused lexical variable xxx
      (ignore last-left space-func top-func uikit-left-of uikit-bottom-of uikit-right-of uikit-top-of)
      ;; during the drawing process `uikit-<constrain>-of' will be
      ;; bind to another function that calculates the constrain into
      ;; actual number and saves to cache
      (dolist (subview (uikit--subview-list-of stackview))
        ;; autolayout yourself if you are a stackview
        (when (cl-typep subview 'uikit-stackview)
          (uikit-autolayout subview))
        ;; set your parent
        (setf (uikit--parent-stackview-of subview) stackview)
        ;; set your left to the right of the previous view
        (uikit-left-of subview last-left)
        (setq last-left (byte-compile (lambda (SELF) (ignore SELF)
                                        (+ (uikit-right-of subview)
                                           (funcall space-func)))))
        ;; top & bottom
        (uikit-top-of subview top-func)))))

When I run it, following warnings pop up:

Warning: Unused lexical variable ‘orientation-index’
Warning: Unused lexical variable ‘orientation-index’
Warning: Unused lexical variable ‘last-left’
Warning: Unused lexical variable ‘stackview’
Warning: Unused lexical variable ‘orientation-index’
Warning: Unused lexical variable ‘last-left’
Warning: Unused lexical variable ‘top-func’
Warning: Unused lexical variable ‘uikit-left-of’
Warning: Unused lexical variable ‘uikit-bottom-of’
Warning: Unused lexical variable ‘uikit-right-of’
Warning: Unused lexical variable ‘uikit-top-of’
Warning: Unused lexical variable ‘--dolist-tail--’
Warning: Unused lexical variable ‘stackview’
Warning: Unused lexical variable ‘orientation-index’
Warning: Unused lexical variable ‘last-left’
Warning: Unused lexical variable ‘top-func’
Warning: Unused lexical variable ‘uikit-left-of’
Warning: Unused lexical variable ‘uikit-bottom-of’
Warning: Unused lexical variable ‘uikit-right-of’
Warning: Unused lexical variable ‘uikit-top-of’

All these variables are those I declared in let binding, and I used them (except uikit-left/top/bottom/right-of). I tried to "use" then with a ignore call, but that doesn't help.

Why am I getting these warnings and how can I fix the problem?

P.S. When I byte compile the file, everything is fine, no warnnings.


UPDATE:

As Stefan and Phill says, when I remove the byte-compile function it doesn't show warnings anymore. And yes, I don't really need to use byte-compile the first place. Thanks! It's interesting that byte-compile compiles closures back into lambda, I never thought it will do that sort of thing.

Yuan Fu
  • 149
  • 10
  • 1
    If you remove all the `(byte-compile ...)` wrappers, I presume the warnings go away? – phils Oct 09 '18 at 06:10
  • 1
    The byte-compiler is telling you about the lexical variables which are not used in the anonymous functions being compiled at run-time. `(lambda (SELF) (ignore SELF) (uikit-left-of stackview))` uses `stackview` but not `orientation-index`, which is where the first warning comes from. You can follow the rest of the sequence from there... – phils Oct 09 '18 at 06:17
  • 2
    I don't *think* there's a purpose to byte-compiling those lambdas at run-time, if you are byte-compiling the whole library? Was there a reason why you did that? I'm sure someone will correct me if I'm missing something, but if the file is compiled then the (implicitly function-quoted) lambdas will be byte-compiled, and those compiled functions are what will be loaded and used at run-time. – phils Oct 09 '18 at 07:33
  • 2
    `(lambda (SELF) (ignore SELF) ...)` with `SELF` not otherwise used is pointless. I guess this was the "I tried to 'use' them with an `ignore` call" part? Prefix unused parameters with an underscore, and the byte-compiler will ignore them. `(lambda (_SELF) ...)` – phils Oct 09 '18 at 07:34

1 Answers1

7

Here's the reason why you get those warnings when you don't byte-compile the file:

My crystal ball tells me this Elisp code is within a file marked as -*- lexical-binding:t -*- (which is a good thing). When the Elisp interpreter evaluates a lambda in this mode, it creates a closure without looking at the body of the lambda so the closure conservatively remembers the whole environment. In your case, for example, the function

(lambda (SELF) (ignore SELF) (uikit-left-of stackview))

will be evaluated to a closure of the form

(closure ((orientation-index . N) ...)
         (SELF)
         (ignore SELF) (uikit-left-of stackview))

where the first element is the environment (aka context) which lists all the surrounding lexically-scoped vars and their respective value.

When you ask the byte-compiler to compile this closure, you're asking it to do something it's not really capable of doing (it's designed to take source code as input, not pre-evaluated values like closures), and the way it handles this case is to turn the closure back into some more-or-less-equivalent source code (this is done in byte-compile--reify-function), more specifically it turns it into:

(lambda (SELF)
  (let ((orientation-index N)
        ...)
    (ignore SELF) (uikit-left-of stackview)))

and then compiles this code. If you look at byte-compile--reify-function it has a FIXME exactly for the problem you mention:

    ;; We check shadowing by the args, so that the `let' can be moved
    ;; within the lambda, which can then be unfolded.  FIXME: Some of those
    ;; bindings might be unused in `body'.

but since byte-compile is something used very rarely (and even more rarely in circumstances like yours), this is rather low priority: in 99.99% of the cases, the better fix is to not use byte-compile.

As you saw, byte-compiling the file removes the problem because in that case byte-compile receives as argument a function that's already compiled so it returns it without doing anything at all.

Stefan
  • 26,154
  • 3
  • 46
  • 84
  • 1
    While useful in explaining the issue, I'd be interested to know how to fix these warnings. – ideasman42 May 16 '19 at 05:12
  • @ideasman42, the fix was mentioned already: don't manually call `byte-compile` on such values (intead, you want to byte-compile the whole file, which will also byte-compile this function but with better knowledge of what's going on). – Stefan May 16 '19 at 12:20
  • 1
    I'm byte compiling the entire file, it's still giving the error. – ideasman42 May 16 '19 at 12:27
  • @ideasman42: then it's a completely different problem from the one discussed here (and BTW, these things are not *errors* but *warnings*) – Stefan May 16 '19 at 12:46