CS 1102: Programming Language Concepts
Notes on Set!

How Set! Works

We've seen that set! is the assignment operator in Racket. These notes give you an overview of what Racket will and will not let you do with set!, and what we (the graders) will and will not let you do with set!.

A set! expression requires two pieces of information: a variable and
an expression:

	(set! var some-exp)

As with all expressions, DrRacket evaluates some-exp first, then
changes the value of var to the value of some-exp.  A set! expression
has (returns) an invisible value.  However, it has a visible effect
because the old definition of var gets erased and replaced with the
value of some-exp.   We can see this by hand-evaluating the following

(define n 5)

  (set! n (+ n 1))

Obviously, this should (and does) return 6.  If we try to
hand-evaluate it to see why, we get

(define n 6)

(begin n)

which returns 6.

So, set! effectively replaces an old define with a new one.  Begin
evaluates each expression in turn (until none are left), throwing away
each expression after it evaluates it.

Let's look at two more example programs:

(define x 3)
(define y 4)

  (set! x y)
  (set! y x))

This becomes

(define x 4)
(define y 4)

  (set! y x))

which in turn becomes

(define x 4)
(define y 4)

Notice that, contrary to possible expectations, the original code does
not swap the values of x and y.  This is because expressions within a
begin are evaluated in order.  The effect of each set! within a begin
occurs before the next one is evaluated.  Let's try writing a swap
program that works.

(define u 4)
(define v 5)

(define (swap x y)
  (local [(define tmp x)]
    (set! x y)
    (set! y tmp)))

(swap u v)

What happens if I check the values of u and v after the call to swap?
They still have their original values.  This happens because set! on a
parameter to a function does not affect anything outside of the
function.  As of now, you don't have the ability to write a swap
function in Racket.

What set! can do in Racket: the summary

What we will let you do with set!

As a general rule of thumb, you should only use set! if you have two functions accessing a variable where one changes the value of the variable and the other accesses the value of the variable. You should not use set! to implement things like loop counters, to accumulate values locally within a function, etc. While your code will run if you do this, it's not functional programming. Basically, if you find yourself trying to write C++ code in Racket, you may be overstepping the bounds of using set!. Ask one of us for help if you're unsure whether you can use set! for a particular purpose.