#15156: Pickling with __reduce__() loops creates invalid pickles
-------------------------------------+-------------------------------------
       Reporter:  vbraun             |        Owner:
           Type:  defect             |       Status:  needs_info
       Priority:  major              |    Milestone:  sage-6.3
      Component:  misc               |   Resolution:
       Keywords:                     |    Merged in:
        Authors:  SimonKing,         |    Reviewers:
  jkeitel, novoselt, nbruin          |  Work issues:
Report Upstream:  N/A                |       Commit:
         Branch:                     |  82ba456b8c828700d28ac36822b300f00d8b1308
  u/saraedum/ticket/15156            |     Stopgaps:
   Dependencies:  #15692             |
-------------------------------------+-------------------------------------

Comment (by saraedum):

 Replying to [comment:17 nbruin]:
 > Replying to [comment:16 saraedum]:
 > > I'm not sure what you mean by "instantiation phase".
 > Unpickling an object happens in two phases: first, the object is
 instantiated using the first set of parameters given by `__reduce__`.
 There can't be circularities here, because that would mean passing an
 object that hasn't been instantiated yet to the routine that does the
 instantiating.
 >
 > The second phase is done by `__setstate__` and allows further
 modification of the state to obtain the desired one. Here, circularities
 are not a problem. The pickler carefully ensures that all objects involved
 in circularities have been instantiated (how would you pass them
 otherwise?)
 > The trick here is that during `__setstate__` you may encounter objects
 that haven't had a chance to run their own `__setstate__` yet.
 I don't think that's really what happens. Maybe I misunderstand what you
 are saying but I don't think that all objects in the pickle are
 instantiated and then all object's `__setstate__` is called.
 Have a look at the example I posted above. There, to unpickle `b`, `a` is
 created, its `__setstate__` is called (which fails), and only then `b` is
 created and its `__setstate__` is called.

 > > There is of course lots of space for improvement, but what do you
 think about this idea?
 > I think it's a bad idea because it doesn't solve the problem where it
 needs to be solved. Homsets fundamentally need domain and codomain for
 their construction. It's part of their hash. If a parent wants to include
 a homset in its construction parameter rather than in the `__setstate__`
 then it is introducing an unavoidable cycle.
 This is not what happens. Here is a real-world example:
 {{{
 sage: class A(Parent):
     def __reduce__(self):
         return A,(),self.homset
     def __setstate__(self, homset):
         self.homset = homset
 ....:
 sage: P=A()
 sage: H=Hom(P,P)
 sage: P.homset = H
 sage: import pickle
 sage: pickle.dumps(H)
 AssertionError
 }}}

 > If the domain and codomain want to store a homset involving them
 somewhere, then their unpickling should do so via `__setstate__`, i.e.,
 their `__reduce__` should include the homset in the second return value,
 not the first.
 That's what happens above and does not work. I'm also confused because I
 always assumed that it would be enough to break the circularity on the
 first parameter in a single place. Somehow this does not seem to work.

--
Ticket URL: <http://trac.sagemath.org/ticket/15156#comment:18>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/d/optout.

Reply via email to