fukamachi / event-emitter

Event mechanism for Common Lisp objects.
BSD 2-Clause "Simplified" License
28 stars 8 forks source link

Event-emitter explodes when a listener tries to remove itself #17

Open NagiNikaido opened 2 months ago

NagiNikaido commented 2 months ago
(defpackage :remove-itself-bug
 (:use :cl :event-emitter))

(in-package :remove-itself-bug)

(defparameter *ev* (make-instance 'event-emitter))

(defun dummy-listener ()
  ())

(defun remove-itself ()
  (remove-listener *ev* :channel #'remove-itself))

(on :channel *ev* #'dummy-listener)
(on :channel *ev* #'remove-itself)
(emit :channel *ev*) ; EXPLODES!

which throws

#<THREAD tid=63927 "main thread" RUNNING {1003F801D3}>:
  Invalid index 1 for (VECTOR T 2) with fill-pointer 1,
  should be a non-negative integer below 1.

Is such removal meant not be supported? Or it seems that the actual removal should be deferred until all recursive emits have been done, considering that codes below are also possible:

(defpackage :another-situation
 (:use :cl :event-emitter))

(in-package :another-situation)

(defparameter *ev* (make-instance 'event-emitter))

(defun dummy-listener (x)
  ())

(defun remove-itself-after-3 (x)
  (format t "~a~%" x)
  (if (< x 3)
      (emit :channel *ev* (1+ x))
      (remove-listener *ev* :channel #'remove-itself-after-3)))

(on :channel *ev* #'dummy-listener)
(on :channel *ev* #'remove-itself-after-3)
(emit :channel *ev* 0) ; EXPLODES!

which prints

0
1
2
3

debugger invoked on a SB-KERNEL:INDEX-TOO-LARGE-ERROR in thread
#<THREAD tid=63927 "main thread" RUNNING {1003F801D3}>:
  Invalid index 1 for (VECTOR T 2) with fill-pointer 1,
  should be a non-negative integer below 1.