21

Suppose I have

(setq a 1 b 2)

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

4
  • 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, 2015 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, 2015 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. Aug 20, 2015 at 19:59
  • 1
    @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, 2015 at 22:54

3 Answers 3

18

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.

0
21

This is the elegant idiom I use ;-).

(setq a  (prog1 b (setq b  a)))
4
  • 1
    Hey, that's neat. I'll keep it in mind if performance is ever a concern.
    – PythonNut
    Aug 20, 2015 at 18:32
  • 1
    Ingenious and simple.
    – Name
    Aug 20, 2015 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, 2015 at 19:51
  • 2
    That's pretty much what cl-rotatef macro expands to.
    – abo-abo
    Aug 21, 2015 at 13:29
6

If it's integers:

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

:)

4
  • 4
    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 Aug 21, 2015 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, 2015 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, 2016 at 15:34
  • @MarkKarpov: (let* ( (a (+ a b)) (b (- a b)) (a (- a b)) ) … )
    – hackerb9
    Aug 12 at 3:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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