diff -r 49120ed41cac -r b81af8b031f2 sage/structure/category_object.pyx
--- a/sage/structure/category_object.pyx	Wed Apr 08 18:49:50 2009 -0700
+++ b/sage/structure/category_object.pyx	Sat Apr 11 14:37:28 2009 -0700
@@ -163,21 +163,43 @@
         return 0
 
     def gens_dict(self):
-         r"""
-         Return a dictionary whose entries are \code{{var_name:variable,...}}.
-         """
-         if HAS_DICTIONARY(self):
+        r"""
+        Return a dictionary whose entries are \code{{var_name:variable,...}}.
+
+        EXAMPLES:
+            sage: ZZ['t'].gens_dict()
+            {'t': t}
+            sage: ZZ['u, v'].gens_dict()
+            {'u': u, 'v': v}
+            sage: ZZ[['XXX']].gens_dict()
+            {'XXX': XXX}
+            sage: RDF['t'].gens_dict()
+            {'t': 1.0*t}
+            sage: CDF.gens_dict()
+            {'I': 1.0*I}
+
+            This is a little odd, but not catastrophic:
+
+            sage: QQ.gens_dict()
+            {'x': 1}
+
+            This fails when the objects are not named:
+
+            sage: (CDF^2).gens_dict()
+            Traceback (most recent call last):
+            ...
+            ValueError: variable names have not yet been set using self._assign_names(...)
+        """
+        if HAS_DICTIONARY(self):
             try:
                 if self._gens_dict is not None:
                     return self._gens_dict
             except AttributeError:
                 pass
-         v = {}
-         for x in self.gens():
-             v[str(x)] = x
-         if HAS_DICTIONARY(self):
+        v = dict(zip(self.variable_names(), self.gens()))
+        if HAS_DICTIONARY(self):
             self._gens_dict = v
-         return v
+        return v
 
     def objgens(self):
         """
diff -r 49120ed41cac -r b81af8b031f2 sage/symbolic/expression.pxd
--- a/sage/symbolic/expression.pxd	Wed Apr 08 18:49:50 2009 -0700
+++ b/sage/symbolic/expression.pxd	Sat Apr 11 14:37:28 2009 -0700
@@ -6,6 +6,8 @@
 cdef class Expression(CommutativeRingElement):
     cdef GEx _gobj
     cdef Expression coerce_in(self, z)
+    cpdef bint is_constant(self)
+    cpdef bint is_symbol(self)
     cpdef bint is_relational(self)
     cpdef object pyobject(self)
     cpdef Expression _subs_expr(self, expr)
diff -r 49120ed41cac -r b81af8b031f2 sage/symbolic/expression.pyx
--- a/sage/symbolic/expression.pyx	Wed Apr 08 18:49:50 2009 -0700
+++ b/sage/symbolic/expression.pyx	Sat Apr 11 14:37:28 2009 -0700
@@ -92,18 +92,16 @@
 include "../ext/stdsage.pxi"
 include "../ext/cdefs.pxi"
 
+import operator
+
 import ring
 import sage.rings.integer
 import sage.rings.rational
 
 from sage.structure.element cimport ModuleElement, RingElement, Element
 from sage.symbolic.function cimport new_SFunction_from_serial
-
-
 from sage.rings.rational import Rational  # Used for sqrt.
-
 from sage.calculus.calculus import CallableSymbolicExpressionRing
-        
 from sage.misc.derivative import multi_derivative
 
 cdef class Expression(CommutativeRingElement):
@@ -262,6 +260,199 @@
             return n
         return sage.rings.rational.Rational(n)
 
+    def _polynomial_(self, R):
+        r"""
+        Coerce this symbolic expression to a polynomial in `R`.
+        
+        EXAMPLES::
+        
+            sage: var('x,y,z,w', ns=1)
+            (x, y, z, w)
+            sage: R = QQ[x,y,z]
+            sage: R(x^2 + y)
+            x^2 + y
+            sage: R = QQ[w]
+            sage: R(1)
+            1
+            sage: R(0*w + 1)
+            1
+            sage: R(w)
+            w
+            sage: R(w + 1)
+            w + 1
+            sage: R(w^2)
+            w^2
+            sage: R(w^3 + w + 1)
+            w^3 + w + 1
+            sage: R = GF(7)[z]
+            sage: R(z^3 + 10*z)
+            z^3 + 3*z
+        
+        .. note::
+
+           If the base ring of the polynomial ring is the symbolic ring,
+           then a constant polynomial is always returned.
+        
+        ::
+        
+            sage: NSR = x.parent()
+            sage: R = NSR[x]
+            sage: a = R(sqrt(2) + x^3 + y)
+            sage: a
+            x^3 + y + sqrt(2)
+            sage: type(a)
+            <class 'sage.rings.polynomial.polynomial_element_generic.Polynomial_generic_dense_field'>
+            sage: a.degree()
+            0
+        
+        We coerce to a double precision complex polynomial ring::
+        
+            sage: f = e*x^3 + pi*y^3 + sqrt(2) + I; f
+            e*x^3 + pi*y^3 + sqrt(2) + I
+            sage: RDF[x](e*x)
+            2.71828182846*x
+            sage: RDF[x](pi*x)
+            3.14159265359*x
+            sage: RDF[x](sqrt(2)*x)
+            1.41421356237*x
+
+            sage: RDF[x, y](f - I)
+            2.71828182846*x^3 + 3.14159265359*y^3 + 1.41421356237
+            sage: CDF[x, y](f)
+            2.71828182846*x^3 + 3.14159265359*y^3 + 1.41421356237 + 1.0*I
+        
+        We coerce to a higher-precision polynomial ring
+        
+        ::
+        
+            sage: RealField(100)[x](e*x)
+            2.7182818284590452353602874714*x
+            sage: RealField(100)[x](pi*x)
+            3.1415926535897932384626433833*x
+            sage: RealField(100)[x](sqrt(2)*x)
+            1.4142135623730950488016887242*x
+            sage: RealField(100)[x,y](f - I)
+            2.7182818284590452353602874714*x^3 + 3.1415926535897932384626433833*y^3 + 1.4142135623730950488016887242
+            sage: ComplexField(100)[x,y](f)
+            2.7182818284590452353602874714*x^3 + 3.1415926535897932384626433833*y^3 + 1.4142135623730950488016887242 + 1.0000000000000000000000000000*I
+
+        This shows that the issue at trac #4246 is fixed (attempting to
+        coerce an expression containing at least one variable that's not in
+        `R` raises an error)::
+        
+            sage: var('x y', ns=1)
+            (x, y)
+            sage: S = PolynomialRing(Integers(4), 1, 'x')
+            sage: S(x)
+            x
+            sage: S(y)
+            Traceback (most recent call last):
+            ...
+            TypeError: y is not a variable of Multivariate Polynomial Ring in x over Ring of integers modulo 4
+            sage: S(x+y)
+            Traceback (most recent call last):
+            ...
+            TypeError: y is not a variable of Multivariate Polynomial Ring in x over Ring of integers modulo 4
+            sage: (x+y)._polynomial_(S)
+            Traceback (most recent call last):
+            ...
+            TypeError: y is not a variable of Multivariate Polynomial Ring in x over Ring of integers modulo 4
+
+        Let's ensure we're not getting fraction field elements:
+
+            sage: x = var('x', ns=1)
+            sage: QQ['x'](1/x)
+            Traceback (most recent call last):
+            ...
+            TypeError: denominator must be a unit
+            sage: QQ['x'](sin(x))
+            Traceback (most recent call last):
+            ...
+            ValueError: Cannot substitue_over_ring with operator 'sin'
+        """
+        vars = self.variables()
+        B = R.base_ring()
+        from ring import NSR
+        if B is NSR:
+            from sage.rings.all import is_MPolynomialRing
+            if is_MPolynomialRing(R):
+                return R({tuple([0]*R.ngens()):self})
+            else:
+                return R([self])
+        R_dict = R.gens_dict()
+        subs_dict = {}
+        for v in vars:
+            try:
+                subs_dict[v] = R_dict[repr(v)]
+            except KeyError:
+                raise TypeError, "%s is not a variable of %s" % (v, R)
+        # this final coercion prevents 1/x from succeeding
+        return R(self.substitute_over_ring(subs_dict, R))
+
+    def substitute_over_ring(self, subs_dict, ring):
+        r"""
+        Iterate over ``self``, converting to ``ring``.
+
+        INPUT:
+
+        ``subs_dict`` should have keys symbols in the symbolic ring
+        and values in ``ring``.  Occurences of ``key`` will be
+        replaced with the corresponding ``value``.
+
+        OUTPUT:
+
+        An element of ``ring``.
+
+        SEEALSO:
+
+        ``_polynomial_()``
+
+        EXAMPLES:
+            sage: x = var('x', ns=1)
+            sage: v = (x^2 - x - 1).substitute_over_ring({x:GF(5)(-1)}, GF(5))
+            sage: v
+            1
+            sage: v.parent()
+            Finite Field of size 5
+
+        TESTS:
+            sage: v = (1/x).substitute_over_ring({x:QQ(2)}, QQ)
+            sage: v
+            1/2
+            sage: v.parent()
+            Rational Field
+            sage: sin(x).substitute_over_ring({x:ZZ(5)}, ZZ)
+            Traceback (most recent call last):
+            ...
+            ValueError: Cannot substitue_over_ring with operator 'sin'
+        """
+        if self.is_constant():
+            return ring(ring.base_ring()(self)) # ring(self) causes an infinite loop
+        if self.is_symbol():
+            return subs_dict[self]
+
+        o = self.operator()
+        if not o in [ operator.add, operator.mul, operator.pow ]:
+            raise ValueError, "Cannot substitue_over_ring with operator '%s'" % repr(o)
+
+        args = list(self)
+
+        if o == operator.pow:
+            # pow must be handled specially
+            if len(args) > 2:
+                raise ValueError, "Power operator must have only two arguments"
+            a = args[0].substitute_over_ring(subs_dict, ring)
+            b = sage.rings.integer.Integer(args[1])
+            return ring( o(a, b) )
+
+        new_args = [ arg.substitute_over_ring(subs_dict, ring) for arg in self ]
+        s = new_args[0]
+        for new_arg in new_args[1:]:
+            # operators only take two arguments, but pynac operators
+            # take variable arguments, so we need to fold/reduce manually
+            s = o(s, new_arg)
+        return ring(s)
+
     def _mpfr_(self, R):
         """
         This is a very preliminary conversion to real numbers.  It
@@ -380,6 +571,52 @@
             e = g_ge(l._gobj, r._gobj)
         return new_Expression_from_GEx(e)
 
+    cpdef bint is_symbol(self):
+        r"""
+        Return True if self is a symbol.
+
+        EXAMPLES:
+            sage: x, y = var('x, y', ns=1)
+            sage: x.is_symbol()
+            True
+            sage: (x/2).is_symbol()
+            False
+            sage: y.is_symbol()
+            True
+            sage: (x + y).is_symbol()
+            False
+
+            sage: (x*0 + 1).is_symbol()
+            False
+            sage: (x*0 + pi).is_symbol()
+            False
+
+            These may be surprising:
+
+            sage: (x/1).is_symbol()
+            True
+            sage: (x + y - y).is_symbol()
+            True
+        """
+        return is_a_symbol(self._gobj)
+
+    cpdef bint is_constant(self):
+        r"""
+        Return True if self is a constant.
+
+        EXAMPLES:
+            sage: x = var('x', ns=1)
+            sage: x.is_constant()
+            False
+            sage: (x*0 + 1).is_constant()
+            True
+            sage: (x*0 + pi).is_constant()
+            True
+            sage: (x + 1).is_constant()
+            False
+        """
+        return self.operator() is None and not self.is_symbol()
+
     cpdef bint is_relational(self):
         """
         Return True if self is a relational expression.
@@ -1257,6 +1494,8 @@
             sage: x,y,z = var('x,y,z',ns=1)
             sage: (x+y).operator()
             <built-in function add>
+            sage: (x-y).operator()
+            <built-in function add>
             sage: (x^y).operator()
             <built-in function pow>
             sage: (x^y * z).operator()
@@ -2307,8 +2546,6 @@
     #def psi2(self, Expression x):
     #    return new_Expression_from_GEx(g_psi2(self._gobj, x._gobj))
 
-
-
 cdef Expression new_Expression_from_GEx(GEx juice):
     cdef Expression nex
     nex = <Expression>PY_NEW(Expression)
diff -r 49120ed41cac -r b81af8b031f2 sage/symbolic/function.pyx
--- a/sage/symbolic/function.pyx	Wed Apr 08 18:49:50 2009 -0700
+++ b/sage/symbolic/function.pyx	Sat Apr 11 14:37:28 2009 -0700
@@ -77,11 +77,11 @@
             sage: foo(x)
             5
 
-            sage: foo = nfunction("foo", 1, evalf_func=lambda x: 5)
+            sage: foo = nfunction("foo", 1, evalf_func=lambda x: 6)
             sage: foo(x)
             foo(x)
             sage: foo(x).n()
-            5
+            6
 
             sage: foo = nfunction("foo", 1, conjugate_func=ev)
             sage: foo(x).conjugate()
