#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 nbruin):

 Replying to [comment:14 saraedum]:
 > cPickle gets things wrong if any circularity is created in the first
 parameter returned by `__reduce__`.
 I think that is more appropriately phrased as "the pickle protocol is not
 defined when construction parameters have circularities". You'd basically
 be asking for a `__new__` call to have an argument that includes the to-
 be-instantiated object. The pickle protocol has a way of introducing
 circularities: via the `__getstate__` and `__setstate__` routines (i.e.,
 the second return value of `__reduce__`).

 > Consider the following code, which creates two objects which reference
 each other:
 > {{{
 > class A(object):
 >     def __reduce__(self):
 >         return A,(),{'b':self.b}
 > class B(object):
 >     def __init__(self,a):
 >         self.a = a
 >     def __reduce__(self):
 >         return B,(self.a,)
 > b=B(A())
 > b.a.b = b
 > }}}
 Note that the circular reference wasn't put there in the corresponding
 `__new__` call. It was a later change of state that caused the circularity
 (this is always necessarily the case). So the circularity should be
 recreated during the `__setstate__` phase of unpickling.

 > This is in particular a problem with Homsets. The `__reduce__` of Hom
 does:
 > {{{
 > return Hom, (self._domain, self._codomain, self.__category, False)
 > }}}
 > Often the domain or codomain reference back to the Homset somehow.

 Domain and codomain cannot possibly refer to the homset in their `__new__`
 call. This is state later introduced, so domain and codomain, if they want
 to put references in to homsets they should do so in the `__setstate__`
 phase.

 > I have no idea how to fix this. The domain is really needed here because
 it determines the class of the result and it is used for a lookup in a
 cache. Any ideas?

 Yes, domain and codomain are really part of a homset, so it's not
 unreasonable to make them part of the `__new__` parameters. If
 circularities arise here, then I'd say the domain and codomain are at
 fault referencing a homset in their instantiation phase. They can't
 possibly have done that when they were originally created either!

 We've see problems before where `__setstate__` values (e.g., python class
 attributes stored in `__dict__` and pickled by default) were needed for
 hash and equality, and the circularities arose on keys in to-be-
 reconstructed dictionaries. Then `__hash__` can be requested on an object
 that hasn't completed its `__setstate__` yet and see `__hash__` fail.
 However, I can't see how homsets can affect the hash of `domain` and
 `codomain`, so that problem shouldn't arise here.

--
Ticket URL: <http://trac.sagemath.org/ticket/15156#comment:15>
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