Would you consider something like this a bad practice?

(defun cycle-list (ls &optional backward?)
  "Given any list, returns the next element each time it is called."
  (let* ((last-pos (- (length ls) 1))
         (maybe-counter (gethash ls cycle-list-counter))
         (cal-counter (if maybe-counter
                          (if backward?
                              (- maybe-counter 1)
                            (+ maybe-counter 1))
         (counter (cond ((> cal-counter last-pos) 0)
                        ((< cal-counter 0) last-pos)
                        (t cal-counter))))
    (puthash ls counter cycle-list-counter)
    (nth counter ls)))

I wrote it because it is pretty handy, e.g. I used it to write another function which cycle between themes.

Surely, it shouldn't be used with simple lists, such as '(1 2 3), or in place of (do-list ...). But also, say we add one more theme to (custom-available-themes), now the previous hash-key is left unused.

I suppose in this particular case of theme cycling, there is probably a way to deal with this but: I want to know if the function (cycle-list ...) itself to you seems bizarre.

  • 1
    Questions here should be specific straighforward how-to questions, that call for specific, straighforward answers. They should not be about what's "best", what's a "good idea", etc., which solicit primarily opinion-based answers.
    – Drew
    Mar 12 '20 at 23:14

There are problems with cycle-list as you have defined it.

  • It seams that you want to apply cycle-list on list variables that you actually do not have control of. What happens if someone uses push, delq, nconc, cl-nset-difference, or similar functions on such a list? Your counter would be invalidated by that.
  • If, because of the previous item, you define your own list, you can choose the type of the list yourself. You actually have a ring-type of list. Depending on the use-case there are built-in types for that. See. e.g., M-: (info "(elisp)Rings") or see how the kill-ring is implemented (M-: (info "(elisp)The Kill Ring") ).
  • The byte-compiler would moan about your code because you use a variable cycle-list-counter that is not declared as special with defvar or defvar-local. (defvar declares the lookup for the symbol-value as always dynamically scoped.)
  • Currently you do not differentiate between global list variables, buffer-local list variables, and list variables that just have buffer-local values in some buffers. Maybe, that aspect could be fixed by declaring cycle-list-counter buffer locally and using either its value or its default-value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.