Protecting variables






(defmspec  $protect (&rest x)
(mapcar #'(lambda (s)
       (cond ((symbolp s)
       (if (get s 'assign)
    (mtell "The variable ~:M is already protected" s)
         (putprop s 'user-protected 'assign)))
      (t
       (mtell "Cannot protect ~:M" s)))) (cdar x))
  '$done)

(defun user-protected (x y)
  (declare (ignore y))
  (merror "Cannot assign a value to the protected variable ~:M" x))

(defmspec $unprotect (&rest x)
  (mapcar #'(lambda (s) (if (and (symbolp s) (eq 'user-protected (get s
  'assign)))
       (remprop s 'assign)
     (mtell "Cannot unprotect ~:M" s))) (cdar x))
  '$done)

Demo:

(C1) load("/home/barton/maxima/protect.lisp")$

(C2) unk : 1$

(C3) protect(unk)$

(C4) unk;

(D4)                           1
(C5) unk : 3;

Cannot assign a value to the protected variable unk
 -- an error.  Quitting.  To debug this try DEBUGMODE(TRUE);)
(C6) unprotect(unk)$

(C7) unk : 3;

(D7)                           3
(C8) unprotect(values);

Cannot unprotect VALUES
(D8)                         DONE
(C9) values : 1;

Improper value assignment to VALUES
 -- an error.  Quitting.  To debug this try DEBUGMODE(TRUE);)
(C10)

Changes:

(1) A user can only unprotect a symbol that has the 'user-protected
property; a user is no longer able to unprotect members infolists.

(2) Protect and unprotect no longer evaluate their arguments.

(3) Protect and unprotect now return done instead of true. I think
this is better.

Bugs:

(1) Protection only protects against assignment; a user can make
assumptions on a protected symbol.

(2) Protect is global -- I think fixing this would require lots of
changes to Maxima.

(C1) f(x) := block([y : 0], protect(y),x);

(D1)             f(x) := BLOCK([y : 0], PROTECT(y), x)
(C2) f(5);

(D2)                           5
(C3) y : 5;

Cannot assign a value to the protected variable y
 -- an error.  Quitting.  To debug this try DEBUGMODE(TRUE);)
(C4)

Other:

I'm undecided whether including this protect / unprotect scheme
would be good or bad for Maxima.

Barton

PS Reading the mset source I learned of the undocumented
option variable SUBSCRMAP

(C1)  subscrmap  : true;

(D1)                         TRUE
(C2) [a,b] : 1;

(D2)                        [1, 1]
(C3) a;

(D3)                           1
(C4) b;

(D4)                           1
(C5) [a,b] : [x,y];

(D5)                     [[x, y], [x, y]]
(C6) a;

(D6)                           y
(C7) b;

(D7)                           y

This is very odd -- the assignment mapping uses outermap1.
Macsyma eliminated  subscrmap and made [a,b] : [x,y] equivalent
 to a : x, b : y.