scorch855
scorch855

Reputation: 322

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

Upvotes: 0

Views: 230

Answers (1)

Robert
Robert

Reputation: 2812

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))

Upvotes: 3

Related Questions