# HG changeset patch
# User Nicolas M. Thiery <nthiery@users.sf.net>
# Date 1335304627 -7200
# Node ID 6b56202511e0e1ac53d24fca5aa438ded5af5948
# Parent  4d6f4c44ce7cf94beedf64a6c9487c472a142a56
#12876: Fix element and parent classes of Hom categories to be abstract, and simplify the Hom logic

Rebased relative #11521
This patch fixes the parent and element classes for Hom categories to
be purely abstract, and simplifies the Hom logic:

- Unified the logic for selecting the class when building a Homset
  (e.g. Homset, RingHomset, HeckeModuleHomspace, ...). This is now
  systematically done through the _Hom_ hook. The logic still has a
  fundamental flaw, but that's for the later #10668.
- The cache for Hom is handled at a single point in Hom
  In particular, homsets created via the _Hom_ hook are now unique.
- If category is None, Hom simply calls itself with the meet of the
  categories of the parent, which removes a cache handling duplication.
- Parent.Hom calls  Hom directly (removes duplicate _Hom_ logic).
- ParentWithBase.Hom was redundant and is gone.
- Reduce the footprint of the current trick to delegate
  Hom(F,F)(on_basis=...) to module_morphism, allow for the diagonal
  option too, an make sure the homset category is set properly.
- Update a doctest in sage.modules.vector_space_homspace to take into
  account that homsets created via _Hom_ are now unique.
- Scheme is (apparently) an abstract base class; so it should not be
  instantiated. I changed some doctests in
  sage.schemes.generic.SchemeMorphism to use instead the concrete
  Spec(ZZ). Those doctests were breaking because Scheme does not
  implement equality, which is required for Hom caching.

As a byproduct, the HeckeModules category does not import any more
HeckeModulesHomspace, which was a recurrent source of import loops.

diff --git a/sage/categories/hecke_modules.py b/sage/categories/hecke_modules.py
--- a/sage/categories/hecke_modules.py
+++ b/sage/categories/hecke_modules.py
@@ -84,6 +84,54 @@
         R = self.base_ring()
         return [ModulesWithBasis(R)]
 
+
+    class ParentMethods:
+
+        def _Hom_(self, Y, category):
+            r"""
+            Returns the homset from ``self`` to ``Y`` in the category ``category``
+
+            INPUT::
+
+            - ``Y`` -- an Hecke module
+            - ``category`` -- a subcategory of :class:`HeckeModules`() or None
+
+            The sole purpose of this method is to construct the homset
+            as a :class:`~sage.modular.hecke.homspace.HeckeModuleHomspace`. If
+            ``category`` is specified and is not a subcategory of
+            :class:`HeckeModules`(), a ``TypeError`` is raised instead
+
+            This method is not meant to be called directly. Please use
+            :func:`sage.categories.homset.Hom` instead.
+
+            EXAMPLES::
+
+                sage: M = ModularForms(Gamma0(7), 4)
+                sage: H = M._Hom_(M, category = HeckeModules(QQ)); H
+                Set of Morphisms from Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field to Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field in Category of Hecke modules over Rational Field
+                sage: H.__class__
+                <class 'sage.modular.hecke.homspace.HeckeModuleHomspace_with_category'>
+                sage: TestSuite(H).run(skip=["_test_zero", "_test_elements"])
+
+            Fixing :meth:'_test_zero' (``__call__`` should accept a
+            function as input) and :meth:`_test_elements` (modular
+            form morphisms elements should inherit from categories) is
+            :trac:'???'.
+
+            TESTS::
+
+                sage: H = M._Hom_(M, category = HeckeModules(GF(5))); H
+                Traceback (most recent call last):
+                ...
+                TypeError: Category of Hecke modules over Finite Field of size 5 is not a subcategory of Category of Hecke modules over Rational Field
+
+            """
+            # TODO: double check that it's the correct HeckeModules category below:
+            if category is not None and not category.is_subcategory(HeckeModules(self.base_ring())):
+                raise TypeError, "%s is not a subcategory of %s"%(category, HeckeModules(self.base_ring()))
+            from sage.modular.hecke.homspace import HeckeModuleHomspace
+            return HeckeModuleHomspace(self, Y, category = category)
+
     class HomCategory(HomCategory):
         def extra_super_categories(self):
             """
@@ -94,6 +142,15 @@
             """
             return [] # FIXME: what category structure is there on Homsets of hecke modules?
 
-        import sage.modular.hecke.homspace
-        class ParentMethods(sage.modular.hecke.homspace.HeckeModuleHomspace):
+
+        def base_ring(self):
+            """
+            EXAMPLES::
+
+                sage: HeckeModules(QQ).hom_category().base_ring()
+                Rational Field
+            """
+            return self.base().base_ring()
+
+        class ParentMethods:
             pass
diff --git a/sage/categories/homset.py b/sage/categories/homset.py
--- a/sage/categories/homset.py
+++ b/sage/categories/homset.py
@@ -67,6 +67,7 @@
 from sage.structure.parent import Parent, Set_generic
 from sage.misc.lazy_attribute import lazy_attribute
 from sage.misc.cachefunc import cached_function
+from sage.misc.constant_function import ConstantFunction
 import types
 
 ###################################
@@ -108,9 +109,9 @@
         Set of Morphisms from Integer Ring to Rational Field in Category of sets
 
         sage: Hom(FreeModule(ZZ,1), FreeModule(QQ,1))
-        Set of Morphisms from Ambient free module of rank 1 over the principal ideal domain Integer Ring to Vector space of dimension 1 over Rational Field in Category of modules with basis over Integer Ring
+        Set of Morphisms from Ambient free module of rank 1 over the principal ideal domain Integer Ring to Vector space of dimension 1 over Rational Field in Category of commutative additive groups
         sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1))
-        Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of vector spaces over Rational Field
+        Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of commutative additive groups
 
     Here, we test against a memory leak that has been fixed at :trac:`11521` by
     using a weak cache::
@@ -151,15 +152,32 @@
         ...
         TypeError: Integer Ring is not in Category of groups
 
+    A parent may specify how to construct certain homsets by
+    implementing a method :meth:`_Hom_`(codomain, category). This
+    method should either construct the requested homset or raise a
+    ``TypeError``. This hook is currently mostly used to create
+    homsets in some specific subclass of :class:`Homset`
+    (e.g. :class:`sage.rings.homset.RingHomset`, ...)::
+
+        sage: Hom(QQ,QQ).__class__
+        <class 'sage.rings.homset.RingHomset_generic_with_category'>
+
+    Do not call this hook directly to create homsets, as it does not
+    handle unique representation::
+
+        sage: Hom(QQ,QQ) == QQ._Hom_(QQ, category=QQ.category())
+        True
+        sage: Hom(QQ,QQ) is QQ._Hom_(QQ, category=QQ.category())
+        False
 
     TESTS:
 
     Some doc tests in :mod:`sage.rings` (need to) break the unique parent assumption.
-    But if domain or codomain are not unique parents, then the hom set won't fit.
+    But if domain or codomain are not unique parents, then the homset won't fit.
     That's to say, the hom set found in the cache will have a (co)domain that is
     equal to, but not identic with, the given (co)domain.
 
-    By trac ticket #9138, we abandon the uniqueness of hom sets, if the domain or
+    By :trac:`9138`, we abandon the uniqueness of hom sets, if the domain or
     codomain break uniqueness::
 
         sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict_domain
@@ -180,12 +198,26 @@
         sage: H1 is H2
         False
 
-    It is always the most recently constructed hom set that remains in the cache::
+    It is always the most recently constructed homset that remains in the cache::
 
         sage: H2 is Hom(QQ,Q)
         True
 
-    Since trac ticket #11900, the meet of the categories of the given arguments is
+    Variation on the theme::
+
+        sage: U1 = FreeModule(ZZ,2)
+        sage: U2 = FreeModule(ZZ,2,inner_product_matrix=matrix([[1,0],[0,-1]]))
+        sage: U1 == U2, U1 is U2
+        (True, False)
+        sage: V = ZZ^3
+        sage: H1 = Hom(U1, V); H2 = Hom(U2, V)
+        sage: H1 == H2, H1 is H2
+        (True, False)
+        sage: H1 = Hom(V, U1); H2 = Hom(V, U2)
+        sage: H1 == H2, H1 is H2
+        (True, False)
+
+    Since :trac:`11900`, the meet of the categories of the given arguments is
     used to determine the default category of the homset. This can also be a join
     category, as in the following example::
 
@@ -204,6 +236,12 @@
     Y, or does the difference only lie in the elements (i.e. the
     morphism), and of course how the parent calls their constructors.
 
+    TESTS::
+
+        sage: R = sage.structure.parent.Set_PythonType(int)
+        sage: S = sage.structure.parent.Set_PythonType(float)
+        sage: Hom(R, S)
+        Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets
     """
     # This should use cache_function instead
     # However it breaks somehow the coercion (see e.g. sage -t sage.rings.real_mpfr)
@@ -220,46 +258,25 @@
         if H.domain() is X and H.codomain() is Y:
             return H
 
-    try:
-        # Apparently X._Hom_ is supposed to be cached
-        return X._Hom_(Y, category)
-    except (AttributeError, TypeError):
-        pass
-
     cat_X = X.category()
     cat_Y = Y.category()
     if category is None:
-        category = cat_X._meet_(cat_Y)
-    elif isinstance(category, Category):
-        if not cat_X.is_subcategory(category):
-            raise TypeError, "%s is not in %s"%(X, category)
-        if not cat_Y.is_subcategory(category):
-            raise TypeError, "%s is not in %s"%(Y, category)
-    else:
+        return Hom(X,Y,category=cat_X._meet_(cat_Y))
+    if not isinstance(category, Category):
         raise TypeError, "Argument category (= %s) must be a category."%category
-    # Now, as the category may have changed, we try to find the hom set in the cache, again:
-    cat_ref = weakref.ref(category) if category is not None else None
-    key = (X,Y,cat_ref)
-    try:
-        H = _cache[key]()
-    except KeyError:
-        H = None
-    if H:
-        # Are domain or codomain breaking the unique parent condition?
-        if H.domain() is X and H.codomain() is Y:
-            return H
-
-    # coercing would be incredibly annoying, since the domain and codomain
-    # are totally different objects
-    #X = category(X); Y = category(Y)
+    if not cat_X.is_subcategory(category):
+        raise TypeError, "%s is not in %s"%(X, category)
+    if not cat_Y.is_subcategory(category):
+        raise TypeError, "%s is not in %s"%(Y, category)
 
     # construct H
     # Design question: should the Homset classes get the category or the homset category?
     # For the moment, this is the category, for compatibility with the current implementations
     # of Homset in rings, schemes, ...
-    H = category.hom_category().parent_class(X, Y, category = category)
-            
-    ##_cache[key] = weakref.ref(H)
+    try:
+        H = X._Hom_(Y, category)
+    except (AttributeError, TypeError):
+        H = Homset(X, Y, category = category)
     _cache[key] = weakref.ref(H)
     return H
 
@@ -383,7 +400,6 @@
             ...
             AttributeError: 'sage.rings.integer.Integer' object has no attribute 'hom_category'
         """
-
         self._domain = X
         self._codomain = Y
         if category is None:
@@ -459,7 +475,7 @@
         """
         return self.__category
 
-    def __call__(self, x=None, y=None, check=True, on_basis=None):
+    def __call__(self, x=None, y=None, check=True, **options):
         """
         Construct a morphism in this homset from x if possible.
         
@@ -507,16 +523,26 @@
             Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of sets
             sage: f(1), f(2), f(3) # todo: not implemented
 
+            sage: H = Hom(ZZ, QQ, Sets())
+            sage: f = H( ConstantFunction(2/3) )
+            sage: f.parent()
+            Set of Morphisms from Integer Ring to Rational Field in Category of sets
+            sage: f(1), f(2), f(3)
+            (2/3, 2/3, 2/3)
 
         - Robert Bradshaw, with changes by Nicolas M. Thiery
         """
-        # Temporary workaround: currently, HomCategory.ParentMethods's cannot override
-        # this __call__ method because of the class inheritance order
-        # This dispatches back the call there
-        if on_basis is not None:
-            return self.__call_on_basis__(on_basis = on_basis)
+        if options:
+            # TODO: this is specific for ModulesWithBasis; generalize
+            # this to allow homsets and categories to provide more
+            # morphism constructors (on_algebra_generators, ...)
+            if 'on_basis' or 'diagonal' in options:
+                return self.__call_on_basis__(category = self.homset_category(),
+                                              **options)
+            else:
+                raise NotImplementedError
+
         assert x is not None
-
         if isinstance(x, morphism.Morphism):
             if x.parent() is self:
                 return x
@@ -536,9 +562,9 @@
                     x = mor * x
                 return x
 
-        if isinstance(x, types.FunctionType) or isinstance(x, types.MethodType):
+        if isinstance(x, (types.FunctionType, types.MethodType, ConstantFunction)):
             return self.element_class_set_morphism(self, x)
-            
+
         raise TypeError, "Unable to coerce x (=%s) to a morphism in %s"%(x,self)
 
     @lazy_attribute
@@ -613,11 +639,11 @@
             sage: type(H)
             <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
             sage: H.reversed()
-            Set of Morphisms from Ambient free module of rank 3 over the principal ideal domain Integer Ring to Ambient free module of rank 2 over the principal ideal domain Integer Ring in Category of hom sets in Category of modules with basis over Integer Ring
+            Set of Morphisms from Ambient free module of rank 3 over the principal ideal domain Integer Ring to Ambient free module of rank 2 over the principal ideal domain Integer Ring in Category of modules with basis over Integer Ring
             sage: type(H.reversed())
             <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
         """
-        return Hom(self.codomain(), self.domain(), category = self.category())
+        return Hom(self.codomain(), self.domain(), category = self.homset_category())
         
     ############### For compatibility with old coercion model #######################
     
diff --git a/sage/categories/modules_with_basis.py b/sage/categories/modules_with_basis.py
--- a/sage/categories/modules_with_basis.py
+++ b/sage/categories/modules_with_basis.py
@@ -884,20 +884,22 @@
         The category of homomorphisms sets Hom(X,Y) for X, Y modules with basis
         """
 
-        class ParentMethods: #(sage.modules.free_module_homspace.FreeModuleHomspace): #    Only works for plain FreeModule's
-            """
-            Abstract class for hom sets
-            """
-
-            def __call__(self, on_basis = None, *args, **options):
+        class ParentMethods:
+            def __call_on_basis__(self, **options):
                 """
-                Construct an element of this homset
+                Construct a morphism in this homset from a function defined on the basis
 
                 INPUT:
 
-                 - on_basis (optional) -- a function from the indices
-                   of the basis of the domain of ``self`` to the
-                   codomain of ``self``
+                - ``on_basis`` -- a function from the indices of the
+                  basis of the domain of ``self`` to the codomain of
+                  ``self``
+
+                This method simply delegates the work to
+                :meth:`ModulesWithBasis.ParentMethods.module_morphism`. It
+                is used by :meth:`Homset.__call__` to handle the
+                ``on_basis`` argument, and will disapear as soon as
+                the logic will be generalized.
 
                 EXAMPLES::
 
@@ -906,6 +908,26 @@
                     sage: H = Hom(X, Y)
                     sage: x = X.basis()
 
+                    sage: phi = H(on_basis = lambda i: Y.monomial(i) + 2*Y.monomial(i+1)) # indirect doctest
+                    sage: phi
+                    Generic morphism:
+                    From: X
+                    To:   Y
+                    sage: phi(x[1] + x[3])
+                    B[1] + 2*B[2] + B[3] + 2*B[4]
+
+                Diagonal functions can be constructed using the ``diagonal`` option::
+
+                    sage: X = CombinatorialFreeModule(QQ, [1,2,3,4]); X.rename("X")
+                    sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4], key="Y"); Y.rename("Y")
+                    sage: H = Hom(X, Y)
+                    sage: x = X.basis()
+                    sage: phi = H(diagonal = lambda x: x^2)
+                    sage: phi(x[1] + x[2] + x[3])
+                    B[1] + 4*B[2] + 9*B[3]
+
+                TESTS::
+
                 As for usual homsets, the argument can be a Python function::
 
                     sage: phi = H(lambda x: Y.zero())
@@ -916,75 +938,23 @@
                     sage: phi(x[1] + x[3])
                     0
 
-                With the on_basis argument, the function can instead
-                be constructed by extending by linearity a function on
-                the basis::
+               We check that the homset category is properly set up::
 
-                    sage: phi = H(on_basis = lambda i: Y.monomial(i) + 2*Y.monomial(i+1))
-                    sage: phi
-                    Generic morphism:
-                    From: X
-                    To:   Y
-                    sage: phi(x[1] + x[3])
-                    B[1] + 2*B[2] + B[3] + 2*B[4]
-
-                This is achieved internaly by using
-                :meth:`ModulesWithBasis.ParentMethods.module_morphism`, which see.
+                    sage: category = FiniteDimensionalModulesWithBasis(QQ)
+                    sage: X = CombinatorialFreeModule(QQ, [1,2,3], category = category);   X.rename("X")
+                    sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4], category = category); Y.rename("Y")
+                    sage: H = Hom(X, Y)
+                    sage: H.zero().category_for()
+                    Category of finite dimensional modules with basis over Rational Field
                 """
-                if on_basis is not None:
-                    args = (self.domain().module_morphism(on_basis, codomain = self.codomain()),) + args
-                h = Homset.__call__(self, *args, **options)
-                if on_basis is not None:
-                    h._on_basis = on_basis
-                return h
-
-            # Temporary hack
-            __call_on_basis__ = __call__
-
-            @lazy_attribute
-            def element_class_set_morphism(self):
-                """
-                A base class for elements of this homset which are
-                also SetMorphism's, i.e. implemented by mean of a
-                Python function.
-
-                This overrides the default implementation
-                :meth:`Homset.element_class_set_morphism`, to also
-                inherit from categories.
-
-                Todo: refactor during the upcoming homset cleanup.
-
-                EXAMPLES::
-
-                    sage: X = CombinatorialFreeModule(QQ, [1,2,3]);   X.rename("X")
-                    sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y")
-                    sage: H = Hom(X, Y)
-                    sage: H.element_class_set_morphism
-                    <class 'sage.categories.morphism.SetMorphism_with_category'>
-                    sage: H.element_class_set_morphism.mro()
-                    [<class 'sage.categories.morphism.SetMorphism_with_category'>,
-                     <type 'sage.categories.morphism.SetMorphism'>,
-                     <type 'sage.categories.morphism.Morphism'>,
-                     <type 'sage.categories.map.Map'>,
-                     <type 'sage.structure.element.Element'>,
-                     <type 'sage.structure.sage_object.SageObject'>,
-                     <class 'sage.categories.modules_with_basis.ModulesWithBasis.HomCategory.element_class'>,
-                     <class 'sage.categories.category.Modules.HomCategory.element_class'>,
-                     <class 'sage.categories.vector_spaces.VectorSpaces.element_class'>,
-                     ...]
-
-                Compare with:
-
-                    sage: H = Hom(ZZ, ZZ)
-                    sage: H.element_class_set_morphism
-                    <type 'sage.categories.morphism.SetMorphism'>
-                """
-                return self.__make_element_class__(SetMorphism, inherit = True)
+                return self.domain().module_morphism(codomain = self.codomain(),
+                                                     **options)
 
         class ElementMethods:
             """
             Abstract class for morphisms of modules with basis
             """
+            @cached_method
             def on_basis(self):
                 """
                 Returns the action of this morphism on basis elements
@@ -1011,11 +981,8 @@
                     sage: g == f
                     True
                 """
-                if not hasattr(self, "_on_basis"):
-                    monomial = self.domain().monomial
-                    self._on_basis = lambda t: self(monomial(t))
-                return self._on_basis
-
+                monomial = self.domain().monomial
+                return lambda t: self(monomial(t))
 
     class CartesianProducts(CartesianProductsCategory):
         """
@@ -1221,8 +1188,6 @@
             B[2]
             sage: phi.on_basis() == phi_on_basis
             True
-
-        Note: could probably be inherited from the categories
         """
         return self._on_basis
 
diff --git a/sage/categories/objects.py b/sage/categories/objects.py
--- a/sage/categories/objects.py
+++ b/sage/categories/objects.py
@@ -86,5 +86,5 @@
             from sets_cat import Sets
             return [Sets()]
 
-        class ParentMethods(Homset):
+        class ParentMethods:
             pass
diff --git a/sage/categories/rings.py b/sage/categories/rings.py
--- a/sage/categories/rings.py
+++ b/sage/categories/rings.py
@@ -92,6 +92,48 @@
             """
             return x*y - y*x
 
+        def _Hom_(self, Y, category):
+            r"""
+            Returns the homset from ``self`` to ``Y`` in the category ``category``
+
+            INPUT::
+
+            - ``Y`` -- a ring
+            - ``category`` -- a subcategory of :class:`Rings`() or None
+
+            The sole purpose of this method is to construct the homset
+            as a :class:`~sage.rings.homset.RingHomset`. If
+            ``category`` is specified and is not a subcategory of
+            :class:`Rings`(), a ``TypeError`` is raised instead
+
+            This method is not meant to be called directly. Please use
+            :func:`sage.categories.homset.Hom` instead.
+
+            EXAMPLES::
+
+                sage: H = QQ._Hom_(QQ, category = Rings()); H
+                Set of Homomorphisms from Rational Field to Rational Field
+                sage: H.__class__
+                <class 'sage.rings.homset.RingHomset_generic_with_category'>
+
+            TESTS::
+
+                sage: Hom(QQ, QQ, category = Rings()).__class__
+                <class 'sage.rings.homset.RingHomset_generic_with_category'>
+
+                sage: Hom(CyclotomicField(3), QQ, category = Rings()).__class__
+                <class 'sage.rings.number_field.morphism.CyclotomicFieldHomset_with_category'>
+
+                sage: TestSuite(Hom(QQ, QQ, category = Rings())).run() # indirect doctest
+
+            """
+            if category is not None and not category.is_subcategory(Rings()):
+                raise TypeError, "%s is not a subcategory of Rings()"%category
+            if Y not in Rings():
+                raise TypeError, "%s is not a ring"%Y
+            from sage.rings.homset import RingHomset
+            return RingHomset(self, Y, category = category)
+
         # this is already in sage.rings.ring.Ring,
         # but not all rings descend from that class,
         # e.g., matrix spaces.
@@ -514,7 +556,6 @@
             """
             raise TypeError, "Use self.quo(I) or self.quotient(I) to construct the quotient ring."
 
-
     class ElementMethods:
         pass
 
@@ -566,13 +607,8 @@
 
             # This should be cleaned up upon the next homset overhaul
 
-            def __new__(cls, X, Y, category):
+            def __new__bx(cls, X, Y, category):
                 """
-                    sage: Hom(QQ, QQ, category = Rings()).__class__                  # indirect doctest
-                    <class 'sage.rings.homset.RingHomset_generic_with_category'>
-
-                    sage: Hom(CyclotomicField(3), QQ, category = Rings()).__class__  # indirect doctest
-                    <class 'sage.rings.number_field.morphism.CyclotomicFieldHomset_with_category'>
                 """
                 from sage.rings.homset import RingHomset
                 return RingHomset(X, Y, category = category)
@@ -583,10 +619,5 @@
                 argument upon unpickling. Maybe it would be preferable to
                 have :meth:`.__new__` accept to be called without arguments.
 
-                TESTS::
-
-                    sage: Hom(QQ, QQ, category = Rings()).__getnewargs__()
-                    (Rational Field, Rational Field, Category of hom sets in Category of rings)
-                    sage: TestSuite(Hom(QQ, QQ, category = Rings())).run() # indirect doctest
                 """
                 return (self.domain(), self.codomain(), self.category())
diff --git a/sage/modules/vector_space_homspace.py b/sage/modules/vector_space_homspace.py
--- a/sage/modules/vector_space_homspace.py
+++ b/sage/modules/vector_space_homspace.py
@@ -329,14 +329,14 @@
             [1 0 2]
 
         Coercing a vector space morphism into the parent of a second vector
-        space morphism will unify their parents. ::
+        space morphism will unify their parents::
 
-            sage: U = QQ^3
-            sage: V = QQ^4
-            sage: W = QQ^3
-            sage: X = QQ^4
+            sage: U = FreeModule(QQ,3, sparse=True ); V = QQ^4
+            sage: W = FreeModule(QQ,3, sparse=False); X = QQ^4
             sage: H = Hom(U, V)
             sage: K = Hom(W, X)
+            sage: H is K, H == K
+            (False, True)
 
             sage: A = matrix(QQ, 3, 4, [0]*12)
             sage: f = H(A)
diff --git a/sage/rings/ring.pyx b/sage/rings/ring.pyx
--- a/sage/rings/ring.pyx
+++ b/sage/rings/ring.pyx
@@ -401,6 +401,20 @@
         # initialisation has finished.
         return self._category or _Rings
 
+    """
+    This temporary alias is here for those instances of :class:`Ring`
+    that are not yet properly in the :class:`Rings`() category.
+
+    TESTS::
+
+        sage: A = Ring(ZZ)
+        sage: A._Hom_.__module__
+        'sage.categories.rings'
+        sage: Hom(A,A).__class__
+        <class 'sage.rings.homset.RingHomset_generic_with_category'>
+    """
+    _Hom_ = Rings.ParentMethods.__dict__['_Hom_']
+
     def ideal_monoid(self):
         """
         Return the monoid of ideals of this ring.
diff --git a/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/sage/schemes/elliptic_curves/ell_curve_isogeny.py
--- a/sage/schemes/elliptic_curves/ell_curve_isogeny.py
+++ b/sage/schemes/elliptic_curves/ell_curve_isogeny.py
@@ -3342,15 +3342,27 @@
 
             sage: E = EllipticCurve(j=GF(7)(0))
             sage: phi = EllipticCurveIsogeny(E, [E(0), E((0,1)), E((0,-1))])
-            sage: phi*phi
-            Traceback (most recent call last):
-            ...
-            NotImplementedError                      
             sage: phi._composition_(phi, phi.parent())
             Traceback (most recent call last):
             ...
             NotImplementedError                      
 
+        The following should test that :meth:`_composition_` is called
+        upon a product. However phi is currently improperly
+        constructed (see :trac:``), which triggers an assertion
+        failure before the actual call ::
+
+            sage: phi*phi
+            Traceback (most recent call last):
+            ...
+            TypeError: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 is not in Category of hom sets in Category of Schemes
+
+        Here would be the desired output::
+
+            sage: phi*phi            # not tested
+            Traceback (most recent call last):
+            ...
+            NotImplementedError
         """
         raise NotImplementedError
 
diff --git a/sage/schemes/generic/morphism.py b/sage/schemes/generic/morphism.py
--- a/sage/schemes/generic/morphism.py
+++ b/sage/schemes/generic/morphism.py
@@ -120,8 +120,7 @@
 
     EXAMPLES::
 
-        sage: from sage.schemes.generic.scheme import Scheme
-        sage: X = Scheme(ZZ)
+        sage: X = Spec(ZZ)
         sage: Hom = X.Hom(X)
         sage: from sage.schemes.generic.morphism import SchemeMorphism
         sage: f = SchemeMorphism(Hom)
@@ -134,8 +133,7 @@
         
         EXAMPLES::
         
-            sage: from sage.schemes.generic.scheme import Scheme
-            sage: X = Scheme(ZZ)
+            sage: X = Spec(ZZ)
             sage: Hom = X.Hom(X)
             sage: from sage.schemes.generic.morphism import SchemeMorphism
             sage: f = SchemeMorphism(Hom)
@@ -158,8 +156,7 @@
 
         EXAMPLES::
 
-            sage: from sage.schemes.generic.scheme import Scheme
-            sage: X = Scheme(ZZ)
+            sage: X = Spec(ZZ)
             sage: Hom = X.Hom(X)
             sage: from sage.schemes.generic.morphism import SchemeMorphism
             sage: f = SchemeMorphism(Hom)
@@ -200,8 +197,7 @@
 
         EXAMPLES::
 
-            sage: from sage.schemes.generic.scheme import Scheme
-            sage: X = Scheme(ZZ)
+            sage: X = Spec(ZZ)
             sage: Hom = X.Hom(X)
             sage: from sage.schemes.generic.morphism import SchemeMorphism
             sage: f = SchemeMorphism(Hom)
diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
--- a/sage/structure/parent.pyx
+++ b/sage/structure/parent.pyx
@@ -1487,11 +1487,13 @@
        raise NotImplementedError("Verification of correctness of homomorphisms from %s not yet implemented."%self)
 
     def Hom(self, codomain, category=None):
-        r"""       
+        r"""
         Return the homspace ``Hom(self, codomain, cat)`` of all
         homomorphisms from self to codomain in the category cat.  The
         default category is :meth:`category``.
 
+        .. SEEALSO:: :func:`~sage.categories.homset.Hom`
+
         EXAMPLES::
         
             sage: R.<x,y> = PolynomialRing(QQ, 2)
@@ -1513,14 +1515,9 @@
             Set of Morphisms from Rational Field to Integer Ring in Category of sets
 
         A parent may specify how to construct certain homsets by
-        implementing a method :meth:`_Hom_`(codomain, category). This
-        method should either construct the requested homset or raise a
-        ``TypeError``.
+        implementing a method :meth:`_Hom_`(codomain, category).
+        See :func:`~sage.categories.homset.Hom` for details.
         """
-        try:
-            return self._Hom_(codomain, category)
-        except (AttributeError, TypeError):
-            pass
         from sage.categories.homset import Hom
         return Hom(self, codomain, category)
 
@@ -2885,22 +2882,6 @@
             # probably
             import sage.rings.infinity
             return sage.rings.infinity.infinity
-            
-#     def _Hom_disabled(self, domain, cat=None):
-#         """
-#         By default, create a homset in the category of sets.
-        
-#         EXAMPLES: 
-#             sage: R = sage.structure.parent.Set_PythonType(int)
-#             sage: S = sage.structure.parent.Set_PythonType(float)
-#             sage: R._Hom_(S)
-#             Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets
-#         """
-#         from sage.categories.sets_cat import Sets
-#         from sage.categories.homset import Homset
-#         if cat is None:
-#             cat = Sets()
-#         return Homset(self, domain, cat)
 
 # These functions are to guarantee that user defined _lmul_, _rmul_,
 # _act_on_, _acted_upon_ do not in turn call __mul__ on their
diff --git a/sage/structure/parent_base.pyx b/sage/structure/parent_base.pyx
--- a/sage/structure/parent_base.pyx
+++ b/sage/structure/parent_base.pyx
@@ -90,40 +90,3 @@
         check_old_coerce(self)
         raise CoercionException, "BUG: the base_extend method must be defined for '%s' (class '%s')"%(
             self, type(self))
-
-    ############################################################################
-    # Homomorphism -- 
-    ############################################################################
-    def Hom(self, codomain, category = None):
-        r"""
-        self.Hom(codomain, category = None):
-        
-        Returns the homspace \code{Hom(self, codomain, category)} of all
-        homomorphisms from self to codomain in the category cat.  The
-        default category is \code{self.category()}.
-
-        EXAMPLES:
-            sage: R.<x,y> = PolynomialRing(QQ, 2)
-            sage: R.Hom(QQ)
-            Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field
-
-        Homspaces are defined for very general \sage objects, even elements of familiar rings.
-            sage: n = 5; Hom(n,7)
-            Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
-            sage: z=(2/3); Hom(z,8/1)
-            Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field
-
-        This example illustrates the optional third argument:
-            sage: QQ.Hom(ZZ, Sets())
-            Set of Morphisms from Rational Field to Integer Ring in Category of sets
-        """
-        # NT 01-2009: what's the difference with parent.Parent.Hom???
-        if self._element_constructor is None:
-            return parent.Parent.Hom(self, codomain, category)
-        try:
-            return self._Hom_(codomain, category)
-        except (AttributeError, TypeError):
-            pass
-        from sage.categories.all import Hom
-        return Hom(self, codomain, category)
-
