Search code examples
racketmutability

Mutability of core functions in Racket


I came across a rather unexpected behavior today, and it utterly contradicted what (I thought) I knew about mutability in Racket.

#lang racket

(define num 8)
;(define num 9) 

Uncommenting the second line gives back the error "module: duplicate definition for identifier in: num", which is fine and expected. After all, define is supposed to treat already defined values as immutable.

However, this makes no sense to me:

#lang racket

(define num 8)
num
(define define 1)
(+ define define)

It returns 8 and 2, but...

  1. define is not set!, and should not allow the redefinition of something already defined, such as define itself.
  2. define is a core language feature, and is clearly already defined, or I should not be able to use num at all.

What gives? Why is define, which is used to create immutable values, not immutable to itself? What is happening here?


Solution

  • When a top-level definition binds an identifier that originates from a macro expansion, the definition captures only uses of the identifier that are generated by the same expansion due to the fresh scope that is generated for the expansion.

    In other words, the transformers (macros) that are required from other modules can be re-defined because they're expanded out by the macro expander (so the issue is not quite about mutability) Moreover, since racket is all about extensibility, there are no reserved keywords and additional functionality can be added to the current define through a macro (or a function) - that's why it can be redefined.

    define is defined as macro of this form - see here.

    #lang racket
    
    (module foo1 racket
      (provide foo1)
      (define-syntaxes (foo1)
        (let ([trans (lambda (syntax-object)
                              (syntax-case syntax-object ()
                                [(_) #'1]))])
          (values trans))))
    
    ; ---
    
    (require 'foo1)
    
    
    (foo1)
    ; => 1
    
    (define foo1 9)
    
    
    (+ foo1 foo1)
    ; => 18