* Checkin remaining documentation
* Add more tests
* Refactor and neaten the code a bit.
* Rename union_update() to update().
* Improve the algorithms (making them a closer to sets.py).
diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex
index 917ca4b..4eb4595 100644
--- a/Doc/lib/libstdtypes.tex
+++ b/Doc/lib/libstdtypes.tex
@@ -1071,6 +1071,126 @@
   \versionadded{2.4}
 \end{description}
 
+\subsection{Set Types \label{types-set}}
+\obindex{set}
+
+A \dfn{set} object is an unordered collection of immutable values.
+Common uses include membership testing, removing duplicates from a sequence,
+and computing mathematical operations such as intersection, union, difference,
+and symmetric difference.
+\versionadded{2.4}     
+
+Like other collections, sets support \code{\var{x} in \var{set}},
+\code{len(\var{set})}, and \code{for \var{x} in \var{set}}.  Being an
+unordered collection, sets do not record element position or order of
+insertion.  Accordingly, sets do not support indexing, slicing, or
+other sequence-like behavior.     
+
+There are currently two builtin set types, \class{set} and \class{frozenset}.
+The \class{set} type is mutable --- the contents can be changed using methods
+like \method{add()} and \method{remove()}.  Since it is mutable, it has no
+hash value and cannot be used as either a dictionary key or as an element of
+another set.  The \class{frozenset} type is immutable and hashable --- its
+contents cannot be altered after is created; however, it can be used as
+a dictionary key or as an element of another set.
+
+Instances of \class{set} and \class{frozenset} provide the following operations:
+
+\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result}
+  \lineiii{len(\var{s})}{}{cardinality of set \var{s}}
+
+  \hline
+  \lineiii{\var{x} in \var{s}}{}
+         {test \var{x} for membership in \var{s}}
+  \lineiii{\var{x} not in \var{s}}{}
+         {test \var{x} for non-membership in \var{s}}
+  \lineiii{\var{s}.issubset(\var{t})}{\code{\var{s} <= \var{t}}}
+         {test whether every element in \var{s} is in \var{t}}
+  \lineiii{\var{s}.issuperset(\var{t})}{\code{\var{s} >= \var{t}}}
+         {test whether every element in \var{t} is in \var{s}}
+
+  \hline
+  \lineiii{\var{s}.union(\var{t})}{\var{s} | \var{t}}
+         {new set with elements from both \var{s} and \var{t}}
+  \lineiii{\var{s}.intersection(\var{t})}{\var{s} \&\ \var{t}}
+         {new set with elements common to \var{s} and \var{t}}
+  \lineiii{\var{s}.difference(\var{t})}{\var{s} - \var{t}}
+         {new set with elements in \var{s} but not in \var{t}}
+  \lineiii{\var{s}.symmetric_difference(\var{t})}{\var{s} \^\ \var{t}}
+         {new set with elements in either \var{s} or \var{t} but not both}
+  \lineiii{\var{s}.copy()}{}
+         {new set with a shallow copy of \var{s}}
+\end{tableiii}
+
+Note, the non-operator versions of \method{union()}, \method{intersection()},
+\method{difference()}, and \method{symmetric_difference()},
+\method{issubset()}, and \method{issuperset()} methods will accept any
+iterable as an argument.  In contrast, their operator based counterparts
+require their arguments to be sets.  This precludes error-prone constructions
+like \code{set('abc') \&\ 'cbs'} in favor of the more readable
+\code{set('abc').intersection('cbs')}.
+
+Both \class{set} and \class{frozenset} support set to set comparisons.
+Two sets are equal if and only if every element of each set is contained in
+the other (each is a subset of the other).
+A set is less than another set if and only if the first set is a proper
+subset of the second set (is a subset, but is not equal).
+A set is greater than another set if and only if the first set is a proper
+superset of the second set (is a superset, but is not equal).
+
+The subset and equality comparisons do not generalize to a complete
+ordering function.  For example, any two disjoint sets are not equal and
+are not subsets of each other, so \emph{all} of the following return
+\code{False}:  \code{\var{a}<\var{b}}, \code{\var{a}==\var{b}}, or
+\code{\var{a}>\var{b}}.
+Accordingly, sets do not implement the \method{__cmp__} method.
+
+Since sets only define partial ordering (subset relationships), the output
+of the \method{list.sort()} method is undefined for lists of sets.
+
+For convenience in implementing sets of sets, the \method{__contains__()},
+\method{remove()}, and \method{discard()} methods automatically match
+instances of the \class{set} class their \class{frozenset} counterparts
+inside a set.  For example, \code{set('abc') in set([frozenset('abc')])}
+returns \code{True}.
+
+The following table lists operations available for \class{set}
+that do not apply to immutable instances of \class{frozenset}:
+
+\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result}
+  \lineiii{\var{s}.update(\var{t})}
+         {\var{s} |= \var{t}}
+         {return set \var{s} with elements added from \var{t}}
+  \lineiii{\var{s}.intersection_update(\var{t})}
+         {\var{s} \&= \var{t}}
+         {return set \var{s} keeping only elements also found in \var{t}}
+  \lineiii{\var{s}.difference_update(\var{t})}
+         {\var{s} -= \var{t}}
+         {return set \var{s} after removing elements found in \var{t}}
+  \lineiii{\var{s}.symmetric_difference_update(\var{t})}
+         {\var{s} \textasciicircum= \var{t}}
+         {return set \var{s} with elements from \var{s} or \var{t}
+          but not both}
+
+  \hline
+  \lineiii{\var{s}.add(\var{x})}{}
+         {add element \var{x} to set \var{s}}
+  \lineiii{\var{s}.remove(\var{x})}{}
+         {remove \var{x} from set \var{s}; raises KeyError if not present}
+  \lineiii{\var{s}.discard(\var{x})}{}
+         {removes \var{x} from set \var{s} if present}
+  \lineiii{\var{s}.pop()}{}
+         {remove and return an arbitrary element from \var{s}; raises
+	  \exception{KeyError} if empty}
+  \lineiii{\var{s}.clear()}{}
+         {remove all elements from set \var{s}}
+\end{tableiii}
+
+Note, the non-operator versions of the \method{update()},
+\method{intersection_update()}, \method{difference_update()}, and
+\method{symmetric_difference_update()} methods will accept any iterable
+as an argument.
+
 
 \subsection{Mapping Types \label{typesmapping}}
 \obindex{mapping}
diff --git a/Include/setobject.h b/Include/setobject.h
index 6289f9c..267e3b0 100644
--- a/Include/setobject.h
+++ b/Include/setobject.h
@@ -20,7 +20,7 @@
 PyAPI_DATA(PyTypeObject) PySet_Type;
 PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
 
-
+#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type)
 #define PyAnySet_Check(ob) \
 	((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type || \
 	  PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 939e490..f3cdc17 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -46,6 +46,11 @@
         self.assertEqual(type(u), self.thetype)
         self.assertRaises(PassThru, self.s.union, check_pass_thru())
         self.assertRaises(TypeError, self.s.union, [[]])
+        for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+            self.assertEqual(self.thetype('abcba').union(C('cdc')), set('abcd'))
+            self.assertEqual(self.thetype('abcba').union(C('efgfe')), set('abcefg'))
+            self.assertEqual(self.thetype('abcba').union(C('ccb')), set('abc'))
+            self.assertEqual(self.thetype('abcba').union(C('ef')), set('abcef'))
 
     def test_or(self):
         i = self.s.union(self.otherword)
@@ -65,6 +70,11 @@
         self.assertEqual(self.s, self.thetype(self.word))
         self.assertEqual(type(i), self.thetype)
         self.assertRaises(PassThru, self.s.intersection, check_pass_thru())
+        for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+            self.assertEqual(self.thetype('abcba').intersection(C('cdc')), set('cc'))
+            self.assertEqual(self.thetype('abcba').intersection(C('efgfe')), set(''))
+            self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc'))
+            self.assertEqual(self.thetype('abcba').intersection(C('ef')), set(''))
 
     def test_and(self):
         i = self.s.intersection(self.otherword)
@@ -85,6 +95,11 @@
         self.assertEqual(type(i), self.thetype)
         self.assertRaises(PassThru, self.s.difference, check_pass_thru())
         self.assertRaises(TypeError, self.s.difference, [[]])
+        for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+            self.assertEqual(self.thetype('abcba').difference(C('cdc')), set('ab'))
+            self.assertEqual(self.thetype('abcba').difference(C('efgfe')), set('abc'))
+            self.assertEqual(self.thetype('abcba').difference(C('ccb')), set('a'))
+            self.assertEqual(self.thetype('abcba').difference(C('ef')), set('abc'))
 
     def test_sub(self):
         i = self.s.difference(self.otherword)
@@ -105,6 +120,11 @@
         self.assertEqual(type(i), self.thetype)
         self.assertRaises(PassThru, self.s.symmetric_difference, check_pass_thru())
         self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
+        for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+            self.assertEqual(self.thetype('abcba').symmetric_difference(C('cdc')), set('abd'))
+            self.assertEqual(self.thetype('abcba').symmetric_difference(C('efgfe')), set('abcefg'))
+            self.assertEqual(self.thetype('abcba').symmetric_difference(C('ccb')), set('a'))
+            self.assertEqual(self.thetype('abcba').symmetric_difference(C('ef')), set('abcef'))
 
     def test_xor(self):
         i = self.s.symmetric_difference(self.otherword)
@@ -191,7 +211,8 @@
 
     def test_clear(self):
         self.s.clear()
-        self.assertEqual(self.s, set([]))
+        self.assertEqual(self.s, set())
+        self.assertEqual(len(self.s), 0)
 
     def test_copy(self):
         dup = self.s.copy()
@@ -201,6 +222,9 @@
     def test_add(self):
         self.s.add('Q')
         self.assert_('Q' in self.s)
+        dup = self.s.copy()
+        self.s.add('Q')
+        self.assertEqual(self.s, dup)
         self.assertRaises(TypeError, self.s.add, [])
 
     def test_remove(self):
@@ -231,13 +255,18 @@
             self.assert_(elem not in self.s)
         self.assertRaises(KeyError, self.s.pop)
 
-    def test_union_update(self):
-        retval = self.s.union_update(self.otherword)
+    def test_update(self):
+        retval = self.s.update(self.otherword)
         self.assertEqual(retval, None)
         for c in (self.word + self.otherword):
             self.assert_(c in self.s)
-        self.assertRaises(PassThru, self.s.union_update, check_pass_thru())
-        self.assertRaises(TypeError, self.s.union_update, [[]])
+        self.assertRaises(PassThru, self.s.update, check_pass_thru())
+        self.assertRaises(TypeError, self.s.update, [[]])
+        for p, q in (('cdc', 'abcd'), ('efgfe', 'abcefg'), ('ccb', 'abc'), ('ef', 'abcef')):
+            for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+                s = self.thetype('abcba')
+                self.assertEqual(s.update(C(p)), None)
+                self.assertEqual(s, set(q))
 
     def test_ior(self):
         self.s |= set(self.otherword)
@@ -254,6 +283,11 @@
                 self.assert_(c not in self.s)
         self.assertRaises(PassThru, self.s.intersection_update, check_pass_thru())
         self.assertRaises(TypeError, self.s.intersection_update, [[]])
+        for p, q in (('cdc', 'c'), ('efgfe', ''), ('ccb', 'bc'), ('ef', '')):
+            for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+                s = self.thetype('abcba')
+                self.assertEqual(s.intersection_update(C(p)), None)
+                self.assertEqual(s, set(q))
 
     def test_iand(self):
         self.s &= set(self.otherword)
@@ -273,6 +307,12 @@
                 self.assert_(c not in self.s)
         self.assertRaises(PassThru, self.s.difference_update, check_pass_thru())
         self.assertRaises(TypeError, self.s.difference_update, [[]])
+        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
+        for p, q in (('cdc', 'ab'), ('efgfe', 'abc'), ('ccb', 'a'), ('ef', 'abc')):
+            for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+                s = self.thetype('abcba')
+                self.assertEqual(s.difference_update(C(p)), None)
+                self.assertEqual(s, set(q))
 
     def test_isub(self):
         self.s -= set(self.otherword)
@@ -292,6 +332,11 @@
                 self.assert_(c not in self.s)
         self.assertRaises(PassThru, self.s.symmetric_difference_update, check_pass_thru())
         self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
+        for p, q in (('cdc', 'abd'), ('efgfe', 'abcefg'), ('ccb', 'a'), ('ef', 'abcef')):
+            for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+                s = self.thetype('abcba')
+                self.assertEqual(s.symmetric_difference_update(C(p)), None)
+                self.assertEqual(s, set(q))
 
     def test_ixor(self):
         self.s ^= set(self.otherword)
@@ -635,7 +680,7 @@
         self.assertEqual(self.set, set([2, 4, 6, 8]))
 
     def test_union_method_call(self):
-        self.set.union_update(set([3, 4, 5]))
+        self.set.update(set([3, 4, 5]))
         self.assertEqual(self.set, set([2, 3, 4, 5, 6]))
 
     def test_intersection_subset(self):
@@ -761,15 +806,15 @@
             self.failUnless(v in popped)
 
     def test_update_empty_tuple(self):
-        self.set.union_update(())
+        self.set.update(())
         self.assertEqual(self.set, set(self.values))
 
     def test_update_unit_tuple_overlap(self):
-        self.set.union_update(("a",))
+        self.set.update(("a",))
         self.assertEqual(self.set, set(self.values))
 
     def test_update_unit_tuple_non_overlap(self):
-        self.set.union_update(("a", "z"))
+        self.set.update(("a", "z"))
         self.assertEqual(self.set, set(self.values + ["z"]))
 
 #==============================================================================
@@ -872,7 +917,7 @@
         self.assertRaises(TypeError, lambda: self.other > self.set)
         self.assertRaises(TypeError, lambda: self.other >= self.set)
 
-    def test_union_update_operator(self):
+    def test_update_operator(self):
         try:
             self.set |= self.other
         except TypeError:
@@ -880,11 +925,11 @@
         else:
             self.fail("expected TypeError")
 
-    def test_union_update(self):
+    def test_update(self):
         if self.otherIsIterable:
-            self.set.union_update(self.other)
+            self.set.update(self.other)
         else:
-            self.assertRaises(TypeError, self.set.union_update, self.other)
+            self.assertRaises(TypeError, self.set.update, self.other)
 
     def test_union(self):
         self.assertRaises(TypeError, lambda: self.set | self.other)
@@ -1215,7 +1260,7 @@
 
     def test_inplace_methods(self):
         for data in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5), 'december'):
-            for methname in ('union_update', 'intersection_update',
+            for methname in ('update', 'intersection_update',
                              'difference_update', 'symmetric_difference_update'):
                 for g in (G, I, Ig, S, L, R):
                     s = set('january')
diff --git a/Objects/setobject.c b/Objects/setobject.c
index fab07fb..01f0588 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -12,48 +12,44 @@
 static PyObject *
 make_new_set(PyTypeObject *type, PyObject *iterable)
 {
-	PyObject *data;
+	PyObject *data = NULL;
 	PyObject *it = NULL;
 	PyObject *item;
-	PySetObject *so;
+	PySetObject *so = NULL;
 
 	/* Get iterator. */
 	if (iterable != NULL) {
 		it = PyObject_GetIter(iterable);
 		if (it == NULL)
-			return NULL;
+			goto done;
 	}
 
 	data = PyDict_New();
-	if (data == NULL) {
-		Py_DECREF(it);
-		return NULL;
-	}
+	if (data == NULL) 
+		goto done;
 
 	while (it != NULL && (item = PyIter_Next(it)) != NULL) {
                 if (PyDict_SetItem(data, item, Py_True) == -1) {
-			Py_DECREF(it);
-			Py_DECREF(data);
 			Py_DECREF(item);
-			return NULL;
+			goto done;
                 } 
 		Py_DECREF(item);
 	}
-	Py_XDECREF(it);
-	if (PyErr_Occurred()) {
-		Py_DECREF(data);
-		return NULL;
-	}
+	if (PyErr_Occurred())
+		goto done;
 
 	/* create PySetObject structure */
 	so = (PySetObject *)type->tp_alloc(type, 0);
-	if (so == NULL) {
-		Py_DECREF(data);
-		return NULL;
-	}
+	if (so == NULL) 
+		goto done;
+
+	Py_INCREF(data);
 	so->data = data;
 	so->hash = -1;
 
+done:
+	Py_XDECREF(data);
+	Py_XDECREF(it);
 	return (PyObject *)so;
 }
 
@@ -64,7 +60,7 @@
 
 	if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
 		return NULL;
-	if (iterable != NULL && iterable->ob_type == &PyFrozenSet_Type) {
+	if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
 		Py_INCREF(iterable);
 		return iterable;
 	}
@@ -161,7 +157,7 @@
 static PyObject *
 frozenset_copy(PySetObject *so)
 {
-	if (so->ob_type == &PyFrozenSet_Type) {
+	if (PyFrozenSet_CheckExact(so)) {
 		Py_INCREF(so);
 		return (PyObject *)so;
 	}
@@ -171,52 +167,6 @@
 PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set.");
 
 static PyObject *
-set_union(PySetObject *so, PyObject *other)
-{
-	PySetObject *result;
-	PyObject *item, *data, *it;
-
-	result = (PySetObject *)set_copy(so);
-	if (result == NULL)
-		return NULL;
-
-	if (PyAnySet_Check(other)) {
-		if (PyDict_Merge(result->data, ((PySetObject *)other)->data, 0) == -1) {
-			Py_DECREF(result);
-			return NULL;
-		}
-		return (PyObject *)result;
-	}
-
-	it = PyObject_GetIter(other);
-	if (it == NULL) {
-		Py_DECREF(result);
-		return NULL;
-	}
-	data = result->data;
-	while ((item = PyIter_Next(it)) != NULL) {
-                if (PyDict_SetItem(data, item, Py_True) == -1) {
-			Py_DECREF(it);
-			Py_DECREF(result);
-			Py_DECREF(item);
-			return NULL;
-                } 
-		Py_DECREF(item);
-	}
-	Py_DECREF(it);
-	if (PyErr_Occurred()) {
-		Py_DECREF(result);
-		return NULL;
-	}
-	return (PyObject *)result;
-}
-
-PyDoc_STRVAR(union_doc,
- "Return the union of two sets as a new set.\n\
-\n\
-(i.e. all elements that are in either set.)");
-
-static PyObject *
 set_union_update(PySetObject *so, PyObject *other)
 {
 	PyObject *item, *data, *it;
@@ -224,8 +174,7 @@
 	if (PyAnySet_Check(other)) {
 		if (PyDict_Merge(so->data, ((PySetObject *)other)->data, 0) == -1) 
 			return NULL;
-		Py_INCREF(so);
-		return (PyObject *)so;
+		Py_RETURN_NONE;
 	}
 
 	it = PyObject_GetIter(other);
@@ -251,6 +200,29 @@
 "Update a set with the union of itself and another.");
 
 static PyObject *
+set_union(PySetObject *so, PyObject *other)
+{
+	PySetObject *result;
+	PyObject *rv;
+
+	result = (PySetObject *)set_copy(so);
+	if (result == NULL)
+		return NULL;
+	rv = set_union_update(result, other);
+	if (rv == NULL) {
+		Py_DECREF(result);
+		return NULL;
+	}
+	Py_DECREF(rv);
+	return (PyObject *)result;
+}
+
+PyDoc_STRVAR(union_doc,
+ "Return the union of two sets as a new set.\n\
+\n\
+(i.e. all elements that are in either set.)");
+
+static PyObject *
 set_or(PySetObject *so, PyObject *other)
 {
 	if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) {
@@ -286,15 +258,25 @@
 	result = (PySetObject *)make_new_set(so->ob_type, NULL);
 	if (result == NULL)
 		return NULL;
-	
+	tgtdata = result->data;
+	selfdata = so->data;
+
+	if (PyAnySet_Check(other) && 
+		PyDict_Size(((PySetObject *)other)->data) > PyDict_Size(selfdata)) {
+		selfdata = ((PySetObject *)other)->data;
+		other = (PyObject *)so;
+	} else if (PyDict_Check(other) &&
+		PyDict_Size(other) > PyDict_Size(selfdata)) {
+		selfdata = other;
+		other = so->data;
+	}
+
 	it = PyObject_GetIter(other);
 	if (it == NULL) {
 		Py_DECREF(result);
 		return NULL;
 	}
 
-	selfdata = so->data;
-	tgtdata = result->data;
 	while ((item = PyIter_Next(it)) != NULL) {
 		if (PySequence_Contains(selfdata, item)) {
 			if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
@@ -390,27 +372,39 @@
 static PyObject *
 set_difference(PySetObject *so, PyObject *other)
 {
-	PySetObject *result;
-	PyObject *item, *tgtdata, *it;
+	PySetObject *result, *otherset=NULL;
+	PyObject *item, *otherdata, *tgtdata, *it;
 
-	result = (PySetObject *)set_copy(so);
+	result = (PySetObject *)make_new_set(so->ob_type, NULL);
 	if (result == NULL)
 		return NULL;
-	
-	it = PyObject_GetIter(other);
+	tgtdata = result->data;
+
+	if (PyDict_Check(other))
+		otherdata = other;
+	else if (PyAnySet_Check(other))
+		otherdata = ((PySetObject *)other)->data;
+	else {
+		otherset = (PySetObject *)make_new_set(so->ob_type, other);
+		if (otherset == NULL) {
+			Py_DECREF(result);
+			return NULL;
+		}
+		otherdata = otherset->data;
+	}	
+
+	it = PyObject_GetIter(so->data);
 	if (it == NULL) {
+		Py_XDECREF(otherset);
 		Py_DECREF(result);
 		return NULL;
 	}
 
-	tgtdata = result->data;
 	while ((item = PyIter_Next(it)) != NULL) {
-		if (PyDict_DelItem(tgtdata, item) == -1) {
-			if (PyErr_ExceptionMatches(PyExc_KeyError))
-				PyErr_Clear();
-			else {
+		if (!PySequence_Contains(otherdata, item)) {
+			if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
+				Py_XDECREF(otherset);
 				Py_DECREF(it);
-				Py_DECREF(result);
 				Py_DECREF(item);
 				return NULL;
 			}
@@ -418,6 +412,7 @@
 		Py_DECREF(item);
 	}
 	Py_DECREF(it);
+	Py_XDECREF(otherset);
 	if (PyErr_Occurred()) {
 		Py_DECREF(result);
 		return NULL;
@@ -489,66 +484,6 @@
 }
 
 static PyObject *
-set_symmetric_difference(PySetObject *so, PyObject *other)
-{
-	PySetObject *result, *otherset=NULL;
-	PyObject *item, *selfdata, *otherdata, *tgtdata, *it;
-
-	selfdata = so->data;
-
-	result = (PySetObject *)set_copy(so);
-	if (result == NULL)
-		return NULL;
-	tgtdata = result->data;
-
-	if (PyDict_Check(other))
-		otherdata = other;
-	else if (PyAnySet_Check(other))
-		otherdata = ((PySetObject *)other)->data;
-	else {
-		otherset = (PySetObject *)make_new_set(so->ob_type, other);
-		if (otherset == NULL) {
-			Py_DECREF(result);
-			return NULL;
-		}
-		otherdata = otherset->data;
-	}	
-
-	it = PyObject_GetIter(otherdata);
-	if (it == NULL) {
-		Py_XDECREF(otherset);
-		Py_DECREF(result);
-		return NULL;
-	}
-
-	while ((item = PyIter_Next(it)) != NULL) {
-		if (PyDict_DelItem(tgtdata, item) == -1) {
-			PyErr_Clear();
-			if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
-				Py_DECREF(it);
-				Py_XDECREF(otherset);
-				Py_DECREF(result);
-				Py_DECREF(item);
-				return NULL;
-			} 
-		}
-		Py_DECREF(item);
-	}
-	Py_DECREF(it);
-	Py_XDECREF(otherset);
-	if (PyErr_Occurred()) {
-		Py_DECREF(result);
-		return NULL;
-	}
-	return (PyObject *)result;
-}
-
-PyDoc_STRVAR(symmetric_difference_doc,
-"Return the symmetric difference of two sets as a new set.\n\
-\n\
-(i.e. all elements that are in exactly one of the sets.)");
-
-static PyObject *
 set_symmetric_difference_update(PySetObject *so, PyObject *other)
 {
 	PyObject *item, *selfdata, *it, *otherdata;
@@ -600,6 +535,83 @@
 "Update a set with the symmetric difference of itself and another.");
 
 static PyObject *
+set_symmetric_difference(PySetObject *so, PyObject *other)
+{
+	PySetObject *result;
+	PyObject *item, *selfdata, *otherdata, *tgtdata, *it, *rv, *otherset;
+
+	if (PyDict_Check(other))
+		otherdata = other;
+	else if (PyAnySet_Check(other))
+		otherdata = ((PySetObject *)other)->data;
+	else {
+		otherset = make_new_set(so->ob_type, other);
+		if (otherset == NULL)
+			return NULL;
+		rv = set_symmetric_difference_update((PySetObject *)otherset, (PyObject *)so);
+		if (rv == NULL)
+			return NULL;
+		Py_DECREF(rv);
+		return otherset;
+	}	
+
+	result = (PySetObject *)make_new_set(so->ob_type, NULL);
+	if (result == NULL)
+		return NULL;
+	tgtdata = result->data;
+	selfdata = so->data;
+
+	it = PyObject_GetIter(otherdata);
+	if (it == NULL) {
+		Py_DECREF(result);
+		return NULL;
+	}
+	while ((item = PyIter_Next(it)) != NULL) {
+		if (!PySequence_Contains(selfdata, item)) {
+			if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
+				Py_DECREF(it);
+				Py_DECREF(item);
+				return NULL;
+			}
+		}
+		Py_DECREF(item);
+	}
+	Py_DECREF(it);
+	if (PyErr_Occurred()) {
+		Py_DECREF(result);
+		return NULL;
+	}
+
+	it = PyObject_GetIter(selfdata);
+	if (it == NULL) {
+		Py_DECREF(result);
+		return NULL;
+	}
+	while ((item = PyIter_Next(it)) != NULL) {
+		if (!PySequence_Contains(otherdata, item)) {
+			if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
+				Py_DECREF(it);
+				Py_DECREF(item);
+				return NULL;
+			}
+		}
+		Py_DECREF(item);
+	}
+	Py_DECREF(it);
+	if (PyErr_Occurred()) {
+		Py_DECREF(result);
+		return NULL;
+	}
+
+	return (PyObject *)result;
+}
+
+PyDoc_STRVAR(symmetric_difference_doc,
+"Return the symmetric difference of two sets as a new set.\n\
+\n\
+(i.e. all elements that are in exactly one of the sets.)");
+
+static PyObject *
 set_xor(PySetObject *so, PyObject *other)
 {
 	if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) {
@@ -1012,7 +1024,7 @@
 	 symmetric_difference_update_doc},
 	{"union",	(PyCFunction)set_union,		METH_O,
 	 union_doc},
-	{"union_update",(PyCFunction)set_union_update,	METH_O,
+	{"update",	(PyCFunction)set_union_update,	METH_O,
 	 union_update_doc},
 	{NULL,		NULL}	/* sentinel */
 };
@@ -1159,8 +1171,7 @@
 	0,				/* ob_size */
 	"frozenset",			/* tp_name */
 	sizeof(PySetObject),		/* tp_basicsize */
-	0,				/* tp_itemsize */
-	/* methods */
+	0,				/* tp_itemsize */	/* methods */
 	(destructor)set_dealloc,	/* tp_dealloc */
 	(printfunc)set_tp_print,	/* tp_print */
 	0,				/* tp_getattr */