Summary

coops + s11n malfunction

Metadata

Description

 #!scheme
 (define-class frotz () ((name accessor: name)))
 (define xyzzy (make frotz 'name "blue jeans"))
 (name xyzzy)
 (with-output-to-file "/tmp/frotz" (lambda () (serialize xyzzy)))
 (define nitfol (with-input-from-file "/tmp/frotz" deserialize))
 nitfol ; <= evals to  #<coops instance of `frotz'>
 (name nitfol); <= fails with Error: (name) no method defined for given argument classes: (#<coops instance of `<standard-class>'>)

This used to work and print "blue jeans" but I'm not sure when it stopped working. I especially hope I can rescue all my other saved objects because I have a lot of precious in there♥

Changes and comments

[2020-08-20 10:05:55 UTC] Idiomdrottning wrote:

OK I've since gone back and checked and what used to work was defstruct, not coops. So this has never been proved to work. It's still a bug, and an interesting one—"nitfol" seems to be a frotz at first but then isn't.

[2020-08-24 16:20:38 UTC] Idiomdrottning wrote:

OK, so the following works in interpreted code and in compiled code up to -O4 after deserialization:

(define (coops-restore! x)
  (##sys#setslot x 1 (eval (class-name (class-of x)))))

After (coops-restore! nitfol) it behaves just like any other frotz, and (name nitfol) returns "blue jeans".

(If frotz is defined in the continuation ofc.)

This isn't recursive so any other instances or class inside of the deserialized object, including in lists, vectors, hashtables etc would also have to be restored.

So the problem with the coops/s11n is with coops' fundamental design. <standard-class> is defined as a recursive structure. The standard class is also an instance of standard class. But, testing to see whether something is the standard class tests for eq with <standard-class> in the environment. That's an eq-relationship that breaks on deserialization.

Deserialization can handle recursive structures (like circular lists) just fine. The S11N egg uses a ref table. But it can't check for eq with structs in the environment. It can handle symbols (somehow…) but not just (eq? a b) where both a and b are names for the same coops#coops-instance.

My idea for a workaround was to try to walk the deserialized coops-instances and replace any references to the fake <standard-class> (which still has the class name <standard-class>, just not environment eq-equality) with the real one. But, all these nonsense recursive structures is making that very difficult.

(The nonsense recursive structures being created by deserializing <standard-class>)

The issue here is with using continuation eq-equality (to a completely cockamamie recursive struct that it itself relies on the aforementioned eq-equality) instead of a symbol in slot 0 like any other datum.

The two solutions I can see is to either make s11n handle coops object specially, by storing a <standard-class> as just a tag (tag number 21 perhaps) instead of as a recursive structure and then restoring it from the environment. Or, ideally, by reworking coops so that <standard-class> is based on having a specific symbol rather than a specific eq-relationship with a structure defined or exported to the continution.