# HG changeset patch
# User Simon King <simon.king@uni-jena.de>
# Date 1325178279 -3600
# Node ID 37e9463019952555098db659704012eb0af9dc3a
# Parent  d74c47d472c9c71e24c3ad7de50727c282ef60b1
[mq]: weak_ref_to_functor.patch

diff --git a/sage/categories/functor.pxd b/sage/categories/functor.pxd
--- a/sage/categories/functor.pxd
+++ b/sage/categories/functor.pxd
@@ -1,5 +1,6 @@
 from sage.structure.sage_object cimport SageObject
 
 cdef class Functor(SageObject):
+    cdef __weakref__
     cdef object __domain
-    cdef object __codomain
\ No newline at end of file
+    cdef object __codomain
diff --git a/sage/structure/coerce.pyx b/sage/structure/coerce.pyx
--- a/sage/structure/coerce.pyx
+++ b/sage/structure/coerce.pyx
@@ -88,7 +88,7 @@
 from parent import Set_PythonType
 from coerce_exceptions import CoercionException
 
-import sys, traceback
+import sys, traceback, weakref
 
 from coerce_actions import LeftModuleAction, RightModuleAction, IntegerMulAction
 
@@ -1205,11 +1205,19 @@
 
         """
         try:
-            return self._action_maps.get(R, S, op)
+            out = self._action_maps.get(R, S, op)()
+            if out is None:
+                action = self.discover_action(R, S, op)
+                action = self.verify_action(action, R, S, op)
+                if action is not None:
+                    self._action_maps.set(R, S, op, weakref.ref(action))
+                return action
+            return out
         except KeyError:
             action = self.discover_action(R, S, op)
             action = self.verify_action(action, R, S, op)
-            self._action_maps.set(R, S, op, action)
+            if action is not None:
+                self._action_maps.set(R, S, op, weakref.ref(action))
             return action
             
     cpdef verify_action(self, action, R, S, op, bint fix=True):
diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
--- a/sage/structure/parent.pyx
+++ b/sage/structure/parent.pyx
@@ -802,7 +802,7 @@
             self._coerce_from_list = []
             self._coerce_from_hash = {}
             self._action_list = []
-            self._action_hash = {}
+            self._action_hash = weakref.WeakValueDictionary()
             self._convert_from_list = []
             self._convert_from_hash = {}
             self._embedding = None
@@ -1756,10 +1756,10 @@
         from sage.categories.action import Action
         if isinstance(action, Action):
             if action.actor() is self:
-                self._action_list.append(action)
+                self._action_list.append(weakref.ref(action))
                 self._action_hash[action.domain(), action.operation(), action.is_left()] = action
             elif action.domain() is self:
-                self._action_list.append(action)
+                self._action_list.append(weakref.ref(action))
                 self._action_hash[action.actor(), action.operation(), not action.is_left()] = action
             else:
                 raise ValueError, "Action must involve self"
@@ -2311,7 +2311,9 @@
             # We do NOT add to the list, as this would lead to errors as in 
             # the example above. 
 
-        self._action_hash[S, op, self_on_left] = action
+            # Since weak references are used, we couldn't store
+            # the result "None"
+            self._action_hash[S, op, self_on_left] = action
         return action
         
 
@@ -2323,7 +2325,10 @@
         from sage.categories.homset import Hom
         from coerce_actions import LeftModuleAction, RightModuleAction
         cdef Parent R
-        for action in self._action_list:
+        for ref in self._action_list:
+            action = ref()
+            if action is None:
+                continue
             if PY_TYPE_CHECK(action, Action) and action.operation() is op:
                 if self_on_left:
                     if action.left_domain() is not self: continue
