Enforced immutability: Difference between revisions
Content added Content deleted
m (C# added the case for readonly members of structs) |
(Add Scheme macro) |
||
Line 1,077: | Line 1,077: | ||
<lang scala>val pi = 3.14159 |
<lang scala>val pi = 3.14159 |
||
val msg = "Hello World"</lang> |
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}}== |
=={{header|Seed7}}== |