David542
David542

Reputation: 110093

Difference between usage of set! and define

In the following code:

(define x 14)
(display x)       ; x = 14

(set! x 13)
(display x)       ; x = 13

(define x 14)
(display x)       ; x = 14
  
(set! y 13)       ; SchemeError: y not found!
(display y)      

What we a use case where someone would want to use set! over just define, if define can be used for everything that set! can be used for + the actual definition itself?

Upvotes: 0

Views: 343

Answers (1)

user5920214
user5920214

Reputation:

define creates a new binding between a name and a value (a variable), set! mutates an existing binding. These are not the same operation, languages like Python which confuse the operations notwithstanding.

In particular something like

(define x 1)
...
(define x 2)

is illegal: you can only create the variable once. Implementations may not check this, but that doesn't make it legal. Once you've created the binding, if you want to modify it you need to do that with set!.

A particular case where implementations (including Racket) are intentionally sloppy about this is when they are being used interactively. Quite often if you're interacting with the system you may want to say, for instance:

> (define square (λ (x) (+ x x)))
... ooops, that's not right, is it?
... Better fix it using the command-line editing
> (define square (λ (x) (* x x)))

In cases like that it's clearly better for the implementation just to allow this repeated definition of things, because it's going to make the life of users enormously easier.

But in programs such repeated definitions in the same scope are (almost?) always bugs, and they really ought to be caught: if you want to mutate a binding, use set!. Racket in particular will certainly puke on these.


Finally note that define is simply not legal in all the places set! is: even in Racket (which allows define in many more places than Scheme does) this is not even slightly legal code:

(define (foo x)
  (define v x)
  (if (odd? x)
      (define v (* v 2))
      (define v (/ v 2)))
  v)

While this is

(define (foo x)
  (define v x)
  (if (odd? x)
      (set! v (* v 2))
      (set! v (/ v 2)))
  v)

(It's still terrible code, but it is legal.).

Upvotes: 2

Related Questions