lispcommon-lispgetteraccessorclisp

Equivalent of getters/accessors in Common Lisp


I am writing a program where each time I access the value of a boolean, no matter how it's accesed, it's value inverts (even if just printing it). In an OOP language the way I would accomplish this would by defining an accessor/getter function for this method. How can I accomplish this in common lisp.

Here is some example code I have written using lisp macros which outputs the expected values, but requires all references to be wrapped like this (A). It would also require me to define a new macro for each boolean. If possible I would like to avoid these two issues.

#!/bin/clisp

(defun getval(x)
  (set x (not (eval x)))
  (return-from getval (eval x)))

(setq a_private 'nil)
(defmacro A() (getval 'a_private))

(format t "A -> ~d~%" (A))
(format t "A -> ~d~%" (A))
(format t "A -> ~d~%" (A))
(format t "A -> ~d~%" (A))

; this returns the following:
; A -> T
; A -> NIL
; A -> T
; A -> NIL


Solution

  • From my understanding, you want to have some variables which toggle from TRUE to FALSE. From the code snippet above I don't really understand what is going on, so I will make the proposals below, I do hope you will find the one which suits you well.

    1. Keep it simple and use simple boolean values
    (defparameter var1 nil)
    (defparameter var2 nil)
    
    (format t "== SIMPLE WAY == ~%")
    (format t "STEP 1~%")
    (format t "A -> ~A~%" var1)
    (format t "B -> ~A~%" var2)
    
    (setf var1 (not var1))
    (setf var2 (not var2))
    
    (format t "STEP 2~%")
    (format t "A -> ~A~%" var1)
    (format t "B -> ~A~%" var2)
    
    (setf var1 (not var1))
    (setf var2 (not var2))
    
    (format t "STEP 3~%")
    (format t "A -> ~A~%" var1)
    (format t "B -> ~A~%" var2)
    
    1. You want to go further and dive into the world of structures
    (format t "== STRUCT AND FUNCTIONS == ~%")
    
    (defstruct status
        (flag nil))
    
    ;; function to toggle the 'flag' from structure of type 'status'
    ;; Returns the new status
    (defun toggle-flag (status-object)
      (let ((previous-flag (status-flag status-object))) ;; get the current flag
        (let ((new-flag (not previous-flag)))            ;; calculate the new flag
          (setf (status-flag status-object) new-flag)    ;; update the new flag
          ;; return value
          new-flag)))
        
    (defparameter var1 (make-status)) ;; create a new object status
    (defparameter var2 (make-status)) ;; create a new object status
    
    (format t "STEP 1~%")
    (format t "A -> ~A~%" (status-flag var1))
    (format t "B -> ~A~%" (status-flag var2))
    
    (format t "STEP 2~%")
    (format t "A -> ~A~%" (toggle-flag var1))
    (format t "B -> ~A~%" (toggle-flag var2))
    
    (format t "STEP 3~%")
    (format t "A -> ~A~%" (toggle-flag var1))
    (format t "B -> ~A~%" (toggle-flag var2))
    
    1. You likes OOP adventures and you want to use classes and methods
    (format t "== CLASSES == ~%")
    
    (defclass state ()           ;; define a new class 'state'
       ((flag                    ;; with a field 'flag'
           :accessor state-flag  ;; accessible with the function (state-flag)
           :initform nil)))      ;; initialized with nil
    
    ;; Method to toggle the 'flag' from object of type 'state'
    ;; Will return the new status
    (defmethod toggle ((object state))
      (let ((previous-status (state-flag object)))
        (let ((new-status (not previous-status)))
          (setf (state-flag object) new-status)
          ;; return value
          new-status)))
    
    (defparameter var1 (make-instance 'state)) ;; create a new object state
    (defparameter var2 (make-instance 'state)) ;; create a new object state
     
    (format t "STEP 1~%")
    (format t "A -> ~A~%" (state-flag var1))
    (format t "B -> ~A~%" (state-flag var2))
    
    (format t "STEP 2~%")
    (format t "A -> ~A~%" (toggle var1))
    (format t "B -> ~A~%" (toggle var2))
    
    (format t "STEP 3~%")
    (format t "A -> ~A~%" (toggle var1))
    (format t "B -> ~A~%" (toggle var2))
    

    All these examples should give you the expected result:

    STEP 1
    A -> NIL
    B -> NIL
    STEP 2
    A -> T
    B -> T
    STEP 3
    A -> NIL
    B -> NIL
    
    1. The last option I could provide would be to use amazing closures:
    (defun make-toggler ()
      (let ((flag nil)) ;; create a new variable (available only to the closure)
        (lambda ()      ;; return a function... which toggle the variable!
          (setf flag (not flag))
          ;; return value
          flag)))
    
    (defparameter var1 (make-toggler))
    (defparameter var2 (make-toggler))
    
    (format t "STEP 1~%")
    (format t "A -> ~A~%" (funcall var1))
    (format t "B -> ~A~%" (funcall var2))
    
    (format t "STEP 2~%")
    (format t "A -> ~A~%" (funcall var1))
    (format t "B -> ~A~%" (funcall var2))
    
    (format t "STEP 3~%")
    (format t "A -> ~A~%" (funcall var1))
    (format t "B -> ~A~%" (funcall var2))