anchor.diff:  (in-package :hinge)
   
   ;; Helpers
  -(defun make-safe-hash-table (&rest args &key)
  +(defun make-safe-hash-table (&rest args &key &allow-other-keys)
     "Wrapper to return a hash table that is safe
   to use concurrently. `args' are passed on as to `make-hash-table'"
     ;; TODO: Feature checks for other lisps
  
positive.code:       (bt:destroy-thread worker)))
    (setf (workers pool) (list))
  
    (format t "Destroying worker sockets.~%")
    (when-let (sock (work-sock pool))
      (zmq:close (work-sock pool)))
    (when-let (sock (result-sock pool))
      (close sock))
  
    (format t "TODO: Fail remaining callbacks in ~A~%" (work pool)))
  
negative.code:    (fail :initarg :fail
           :initform (lambda (condition) (declare (ignore condition)))
           :documentation "Invoked on a failed run of `thunk' with the condition signaled in the original thread.")))
  
  ;;; API
  (defmacro async ((&key hinge pool success failure) &body forms)
    (with-gensyms (g!job-id g!job e!pool e!hinge e!success e!failure)
      `(let* ((,e!hinge ,hinge)
              (,e!pool (or ,pool
                           (bg-pool (if ,e!hinge ,e!hinge (get-default-hinge)))))
              (,e!success ,success)
              (,e!failure ,failure)
  
              (,g!job-id (princ-to-string (uuid:make-v4-uuid)))
              (,g!job (apply #'make-instance 'job :id ,g!job-id
                             :thunk (lambda () ,@forms)
                             (flatten
                              (remove nil (list
                                           (when ,e!success (list :finish ,e!success))
                                           (when ,e!failure (list :fail ,e!failure))))))))
         (setf (gethash ,g!job-id (work ,e!pool)) ,g!job)
         (format t "Sending job: ~S to pool ~S~%" ,g!job-id ,e!pool)
         (zmq:send! (work-sock ,e!pool) ,g!job-id)
         ,g!job-id)))
  