17

Suppose I have

(setq a 1 b 2)

How can I elegantly swap the values of a and b without using a temporary variable?

  • While I remember the swap operation from programming examples many many years ago, I don't think I've ever needed such a "swap" operation. So where do you find you need such a thing? – Stefan Aug 20 '15 at 19:55
  • @Stefan this time, I'm writing a function that takes two arguments, and I'd like to ensure that the first argument is the smaller of the two. – PythonNut Aug 20 '15 at 19:57
  • 1
    @PythonNut, well you can bind first argument to (min a b) and second to (max a b). This is one solution. Some will argue that this requires two comparisons when one suffices, that's right. You can handle it with one comparison in more functional manner still, for example using destructuring bind (cl-destructuring-bind (a . b) (if (< a b) (cons a b) (cons b a)) ...). This is another way. – Mark Karpov Aug 20 '15 at 19:59
  • @Mark true, but, at least to me, that feels like swatting flies with hand grenades. cl-destructuring-bind is a ridiculously powerful tool for this job. – PythonNut Aug 20 '15 at 22:54
16

If memory serves me well and you're willing to use cl-lib then:

(cl-rotatef a b)

Note that this is Common Lisp way of solving the problem.

19

This is the elegant idiom I use ;-).

(setq a  (prog1 b (setq b  a)))
  • 1
    Hey, that's neat. I'll keep it in mind if performance is ever a concern. – PythonNut Aug 20 '15 at 18:32
  • Ingenious and simple. – Name Aug 20 '15 at 18:52
  • 1
    Oh, it's not original with me, by any means. But it is probably the main use I make of prog1. – Drew Aug 20 '15 at 19:51
  • 1
    That's pretty much what cl-rotatef macro expands to. – abo-abo Aug 21 '15 at 13:29
4

If it's integers:

(setq a (logxor a b))
(setq b (logxor a b))
(setq a (logxor a b))

:)

  • For completeness you should also include the following classic: a = a + b, b = a - b, a = a - b. Translated to Emacs Lisp, of course :-D – Mark Karpov Aug 21 '15 at 9:15
  • 1
    True, and for completeness I'll point out that in asm or C the The XOR Trick works for anything; registers, memory, ints, floats, structs, strings(equal length)... In Lisp I think only ints. For large blocks of memory it's nice to not need the temp buffer. – jtgd Aug 21 '15 at 20:07
  • @jtgd: For large blocks of memory, you can do the swap segment-by-segment, with a small buffer. – Clément Jul 27 '16 at 15:34

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.