Новогодний code snippet: деструкторы C++ в CL

(defgeneric dispose (object)
  (:documentation "Disposes an object.")
  (:method ((object T)) (values)))

(defun %ensure-bindings (bindings)
  (loop :for b :in bindings
    :collect (etypecase b
               (symbol (list b nil))
               (cons b))))

(defmacro letd ((&rest bindings) &body body)
  (let ((bindings (%ensure-bindings bindings)))
    `(let ,bindings
       (unwind-protect
           (locally ,@body)
         (progn ,@(loop :for b :in bindings
                        :collect `(dispose ,(car b))))))))

(defmacro letd* ((&rest bindings) &body body)
  (let ((bindings (%ensure-bindings bindings)))
    `(let* ,bindings
       (unwind-protect
           (locally ,@body)
         (progn ,@(loop :for b :in bindings
                        :collect `(dispose ,(car b))))))))


Ну и пример использования, вот такой:

;; что хорошо в CLOS, так это то, что, поскольку методы классам
;; не принадлежат, мы можем «добавлять» методы к уже существующим классам
(defmethod dispose ((object stream))
  (close object))


(letd ((in (open "HelloWorld.txt")))
  (read-line in)) ;;
после выхода из тела макроса поток закрывается

Для настройки форматирования в емаксе надо в define-common-lisp-style(в недавней статье про настройку SBCL+Emacs под Windows я это упоминал) добавить следующее:

(letd (as let))
    (letd* (as let*))


Всех с наступившим!
  • avatar
  • +1

1 комментарий

avatar
Интересно
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.