Redefining a structure permanently breaks method specialized on it
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Fix Released
|
Wishlist
|
Unassigned |
Bug Description
Suppose there's a structure, and a method specialized on this structure.
I added a new field to this structure. This causes an error, and I choose CONTINUE restart to invalidate the existing instances of the structure. I also recompile the method, just to be safe.
However this leaves the method in a broken state. It can be called exactly once before having to be recompiled again!
Here's an example:
(defstruct test-struct abc)
(defgeneric fun-struct (struct) (:method ((s test-struct)) s))
(fun-struct (make-test-struct :abc 123)) ;; works
(defstruct test-struct abc blah) ;; invoke CONTINUE restart here
(defgeneric fun-struct (struct) (:method ((s test-struct)) s)) ;; recompiling the method
(fun-struct (make-test-struct :abc 123)) ;; works
(fun-struct (make-test-struct :abc 123)) ;; error!
debugger invoked on a SB-PCL:
#<THREAD "main thread" RUNNING {1000508083}>:
There is no applicable method for the generic function
#<STANDARD-
when called with arguments
(#S(TEST-STRUCT :ABC 123 :BLAH NIL)).
== Notes ==
1. Choosing RECKLESSLY-CONTINUE restart doesn't cause this error.
2. The method needs to be called at least once before the structure redefinition otherwise this doesn't happen.
3. Uninterning 'test-struct and recompiling the structure and method fixes this error. Otherwise it is extremely persistent (even renaming the method doesn't help!)
4. The more automated test case with HANDLER-BIND invoking CONTINUE requires redefining the structure one more time, otherwise even the first method call would fail with
debugger invoked on a SB-PCL:
#<THREAD "main thread" RUNNING {1000508083}>:
obsolete structure error for a structure of type TEST-STRUCT
I don't know why the behavior is different compared to manually choosing CONTINUE restart.
(defstruct test-struct abc)
(defgeneric fun-struct (struct) (:method ((s test-struct)) s))
(fun-struct (make-test-struct :abc 123)) ;; works
(handler-bind ((simple-error (invoke-restart 'continue)))
(defstruct test-struct abc blah))
(defstruct test-struct abc blah) ;; this is required to avoid OBSOLETE-STRUCTURE error
(defgeneric fun-struct (struct) (:method ((s test-struct)) s))
(fun-struct (make-test-struct :abc 123)) ;; works
(fun-struct (make-test-struct :abc 123)) ;; fails
== System info ==
I detected this on SBCL 2.0.0 on Windows 7 but checked the latest version on Linux just in case.
$ sbcl --version
SBCL 2.0.3
$ uname -a
Linux harime 5.1.17-
* *features*
(:QUICKLISP :SB-BSD-
:ASDF :OS-UNIX :NON-BASE-
:ANSI-CL :COMMON-LISP :ELF :IEEE-FLOATING-
:PACKAGE-
:SBCL :UNIX)
Changed in sbcl: | |
importance: | Undecided → Wishlist |
status: | Won't Fix → Triaged |
Changed in sbcl: | |
status: | Triaged → Fix Committed |
Changed in sbcl: | |
status: | Fix Committed → Fix Released |
See http:// www.lispworks. com/documentati on/HyperSpec/ Body/m_ defstr. htm#defstruct
"The consequences of redefining a defstruct structure are undefined."