Subject: Re: bug#29220: 26.0.90; eieio-persistent-read fail to restore saved object.

From: Eric Abrahamsen <[email-masked]>
Date: Sat, 18 Nov 2017 10:14:49 -0800

Noam Postavsky <[email-masked]> writes:

> Eric Abrahamsen <[email-masked]> writes:
>
>> (Are you guys looking at a different version of the pcache repo? The one
>> on Github uses `constructor', not `make-instance'.)
>
> The version mentioned in #23:
>
>     I've put an branch (pte/emacs-26) on github
>     (https://github.com/PierreTechoueyres/pcache.git) with some tests that
>     you can launch with

Oops, I missed that.

[...]

>> But I still think the problem isn't in reading, it's in writing: the
>> entries in the hash table are being written incorrectly, and so this
>> validation step is exploding.
>
> Yes, the way structs and classes are encoded in emacs-26 changed, so the
> way they're written changed also.  It seems the round-tripping loses the
> class/type maybe?  I can still see the '44' entry in the hash table, so
> the hash table itself is still in there...

Here's what I think is going on:

(defclass person ()
  ((name :type string :initarg :name)))

(defclass classy (eieio-persistent)
  ((teacher
    :type person
    :initarg :teacher)
   (students
    :initarg :students :initform (make-hash-table))))

(setq jane (make-instance 'person :name "Jane"))
(setq bob (make-instance 'person :name "Bob"))

(setq class (make-instance 'classy
			   :teacher jane))
(puthash "Bob" bob (slot-value class 'students))

(object-write class) =>
(classy "classy-52080cc"
  :teacher
  (person "person-52080c4"
    :name "Jane")
  :students #s(hash-table size 65 test eql rehash-size 1.5
  rehash-threshold 0.8125 data ("Bob" #s(#s(eieio--class person nil nil
  [#s(cl-slot-descriptor name unbound string nil)] #s(hash-table size 65
  test eq rehash-size 1.5 rehash-threshold 0.8125 data (name 0)) nil
  ((:name . name)) [] [] #s(#2 unbound) (:custom-groups nil)) "Bob"))))

Jane is `read'-able, Bob isn't. `object-write' will recurse and use
`object-write' on any member objects, but the hashtable gets sent to
`prin1', which I assume uses `prin1' on all its values instead:

(object-write bob) =>
(person "person-482ca1c" :name "Bob")

(prin1 bob) =>
#s(#s(eieio--class person nil nil [#s(cl-slot-descriptor
name unbound string nil)] #s(hash-table size 65 test eq rehash-size 1.5
rehash-threshold 0.8125 data (name 0 ...)) nil ((:name . name)) [] []
#s(#1 unbound) (:custom-groups nil)) "Bob")

And I see I have yet again screwed up the changes to `object-write' in
master; off to fix that now.