Enforced immutability: Difference between revisions

Add Scheme macro
m (C# added the case for readonly members of structs)
(Add Scheme macro)
Line 1,077:
<lang scala>val pi = 3.14159
val msg = "Hello World"</lang>
 
=={{header|Scheme}}==
The easiest way of enforcing immutability is simply not importing mutative procedures (helpfully prefixed with <tt>!</tt>) when importing the main libraries.
It helps that imported variables are immutable by standard.
However, you might want to prevent yourself from accidentally calling <tt>set!</tt> on local variables for whatever reason.
Below is a <tt>syntax-case</tt> macro that uses variable transformers to disable <tt>set!</tt> calls on the given token, with a descriptive error message.
It can also be adapted to work with other mutative procedures.
The value itself is neatly tucked behind a hygienically mangled identifier that is impossible to directly reach.
 
This R6RS macro can be effortlessly ported to [[Racket]] by replacing <tt>make-variable-transformer</tt> with <tt>make-set!-transformer</tt> and <tt>(raise (syntax-violation ...))</tt> with <tt>(raise-syntax-error ...)</tt>.
<lang scheme>(define-syntax define-constant
(syntax-rules ()
((_ id v)
(begin
(define _id v)
(define-syntax id
(make-variable-transformer
(lambda (stx)
(syntax-case stx (set!)
((set! id _)
(raise
(syntax-violation
'set! "Cannot redefine constant" stx #'id)))
((id . args) #'(_id . args))
(id #'_id)))))))))</lang>
Example use case:
<lang scheme>(define-constant fnord 23)
;;
fnord
;; => 23
(+ fnord 5)
;; => 28
(set! fnord 42)
;; => Syntax error: set!: Cannot redefine constant in subform fnord of (set! fnord 42)</lang>
It works with procedures as well:
<lang scheme>(define-constant square (lambda (n) (* n n)))
;;
square
;; => #<procedure square>
(square 5)
;; => 25
(set! square (lambda (n) (* n n n)))
;; => Syntax error: set!: Cannot redefine constant in subform square of (set! square (lambda (n) (* n n n)))</lang>
 
=={{header|Seed7}}==
Anonymous user