[libgdata] [core] Add a GDataComparable interface



commit 36bb9c9fe745cf42970b6088f805877e6f2f669b
Author: Philip Withnall <philip tecnocode co uk>
Date:   Tue Jun 15 13:29:03 2010 +0100

    [core] Add a GDataComparable interface
    
    Add a GDataComparable interface and use it to replace all the tiny *_compare()
    functions for various classes. They've consequently been removed from the API
    in a pretty massive API break.

 Makefile.am                                      |    4 +-
 docs/reference/gdata-docs.xml                    |    1 +
 docs/reference/gdata-sections.txt                |   33 ++--
 gdata/atom/gdata-author.c                        |   49 ++----
 gdata/atom/gdata-author.h                        |    1 -
 gdata/atom/gdata-category.c                      |   49 ++----
 gdata/atom/gdata-category.h                      |    1 -
 gdata/atom/gdata-generator.c                     |   49 ++----
 gdata/atom/gdata-generator.h                     |    2 -
 gdata/atom/gdata-link.c                          |   55 +++----
 gdata/atom/gdata-link.h                          |    1 -
 gdata/gcontact/gdata-gcontact-calendar.c         |   58 +++----
 gdata/gcontact/gdata-gcontact-calendar.h         |    1 -
 gdata/gcontact/gdata-gcontact-external-id.c      |   59 +++-----
 gdata/gcontact/gdata-gcontact-external-id.h      |    1 -
 gdata/gcontact/gdata-gcontact-language.c         |   56 +++----
 gdata/gcontact/gdata-gcontact-language.h         |    1 -
 gdata/gcontact/gdata-gcontact-website.c          |   58 +++----
 gdata/gcontact/gdata-gcontact-website.h          |    1 -
 gdata/gd/gdata-gd-email-address.c                |   49 ++----
 gdata/gd/gdata-gd-email-address.h                |    1 -
 gdata/gd/gdata-gd-im-address.c                   |   56 +++----
 gdata/gd/gdata-gd-im-address.h                   |    1 -
 gdata/gd/gdata-gd-name.c                         |   58 +++----
 gdata/gd/gdata-gd-name.h                         |    1 -
 gdata/gd/gdata-gd-organization.c                 |   56 +++----
 gdata/gd/gdata-gd-organization.h                 |    1 -
 gdata/gd/gdata-gd-phone-number.c                 |   49 ++----
 gdata/gd/gdata-gd-phone-number.h                 |    1 -
 gdata/gd/gdata-gd-postal-address.c               |   58 +++----
 gdata/gd/gdata-gd-postal-address.h               |    1 -
 gdata/gd/gdata-gd-reminder.c                     |   83 ++++------
 gdata/gd/gdata-gd-reminder.h                     |    1 -
 gdata/gd/gdata-gd-when.c                         |   74 +++-----
 gdata/gd/gdata-gd-when.h                         |    1 -
 gdata/gd/gdata-gd-where.c                        |   56 +++----
 gdata/gd/gdata-gd-where.h                        |    1 -
 gdata/gd/gdata-gd-who.c                          |   56 +++----
 gdata/gd/gdata-gd-who.h                          |    1 -
 gdata/gdata-comparable.c                         |   95 +++++++++++
 gdata/gdata-comparable.h                         |   66 ++++++++
 gdata/gdata-entry.c                              |    7 +-
 gdata/gdata.h                                    |    1 +
 gdata/gdata.symbols                              |   20 +--
 gdata/services/calendar/gdata-calendar-event.c   |    7 +-
 gdata/services/contacts/gdata-contacts-contact.c |   19 +-
 gdata/tests/general.c                            |  196 ++++++----------------
 47 files changed, 615 insertions(+), 881 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 97479da..356892f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -155,7 +155,8 @@ gdata_headers = \
 	gdata/gdata-access-rule.h	\
 	gdata/gdata-parsable.h		\
 	gdata/gdata-download-stream.h	\
-	gdata/gdata-upload-stream.h
+	gdata/gdata-upload-stream.h	\
+	gdata/gdata-comparable.h
 # The following headers are private, and shouldn't be installed:
 private_headers = \
 	gdata/gdata-private.h		\
@@ -285,6 +286,7 @@ gdata_libgdata_la_SOURCES = \
 	gdata/gdata-download-stream.c	\
 	gdata/gdata-upload-stream.c	\
 	gdata/gdata-buffer.c		\
+	gdata/gdata-comparable.c	\
 	\
 	gdata/atom/gdata-author.c	\
 	gdata/atom/gdata-category.c	\
diff --git a/docs/reference/gdata-docs.xml b/docs/reference/gdata-docs.xml
index 2a62fc2..40d7890 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -33,6 +33,7 @@
 			<xi:include href="xml/gdata-parsable.xml"/>
 			<xi:include href="xml/gdata-download-stream.xml"/>
 			<xi:include href="xml/gdata-upload-stream.xml"/>
+			<xi:include href="xml/gdata-comparable.xml"/>
 		</chapter>
 
 		<chapter>
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 941c91a..3276713 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -729,7 +729,6 @@ GDataCalendarFeedPrivate
 GDataCategory
 GDataCategoryClass
 gdata_category_new
-gdata_category_compare
 gdata_category_get_term
 gdata_category_set_term
 gdata_category_get_scheme
@@ -754,7 +753,6 @@ GDataCategoryPrivate
 GDataLink
 GDataLinkClass
 gdata_link_new
-gdata_link_compare
 gdata_link_get_uri
 gdata_link_set_uri
 gdata_link_get_relation_type
@@ -792,7 +790,6 @@ GDataLinkPrivate
 GDataAuthor
 GDataAuthorClass
 gdata_author_new
-gdata_author_compare
 gdata_author_get_name
 gdata_author_set_name
 gdata_author_get_uri
@@ -816,7 +813,6 @@ GDataAuthorPrivate
 <TITLE>GDataGenerator</TITLE>
 GDataGenerator
 GDataGeneratorClass
-gdata_generator_compare
 gdata_generator_get_name
 gdata_generator_get_uri
 gdata_generator_get_version
@@ -840,7 +836,6 @@ GDATA_GD_ORGANIZATION_OTHER
 GDataGDOrganization
 GDataGDOrganizationClass
 gdata_gd_organization_new
-gdata_gd_organization_compare
 gdata_gd_organization_get_name
 gdata_gd_organization_set_name
 gdata_gd_organization_get_title
@@ -886,7 +881,6 @@ GDATA_GD_EVENT_TRANSPARENCY_TRANSPARENT
 GDataGDWhen
 GDataGDWhenClass
 gdata_gd_when_new
-gdata_gd_when_compare
 gdata_gd_when_get_start_time
 gdata_gd_when_set_start_time
 gdata_gd_when_get_end_time
@@ -919,7 +913,6 @@ GDATA_GD_WHO_EVENT_SPEAKER
 GDataGDWho
 GDataGDWhoClass
 gdata_gd_who_new
-gdata_gd_who_compare
 gdata_gd_who_get_relation_type
 gdata_gd_who_set_relation_type
 gdata_gd_who_get_value_string
@@ -947,7 +940,6 @@ GDATA_GD_WHERE_EVENT_PARKING
 GDataGDWhere
 GDataGDWhereClass
 gdata_gd_where_new
-gdata_gd_where_compare
 gdata_gd_where_get_relation_type
 gdata_gd_where_set_relation_type
 gdata_gd_where_get_value_string
@@ -975,7 +967,6 @@ GDATA_GD_EMAIL_ADDRESS_WORK
 GDataGDEmailAddress
 GDataGDEmailAddressClass
 gdata_gd_email_address_new
-gdata_gd_email_address_compare
 gdata_gd_email_address_get_address
 gdata_gd_email_address_set_address
 gdata_gd_email_address_get_relation_type
@@ -1016,7 +1007,6 @@ GDATA_GD_IM_PROTOCOL_JABBER
 GDataGDIMAddress
 GDataGDIMAddressClass
 gdata_gd_im_address_new
-gdata_gd_im_address_compare
 gdata_gd_im_address_get_address
 gdata_gd_im_address_set_address
 gdata_gd_im_address_get_protocol
@@ -1054,7 +1044,6 @@ GDATA_GD_MAIL_CLASS_PARCELS
 GDataGDPostalAddress
 GDataGDPostalAddressClass
 gdata_gd_postal_address_new
-gdata_gd_postal_address_compare
 gdata_gd_postal_address_get_address
 gdata_gd_postal_address_set_address
 gdata_gd_postal_address_get_relation_type
@@ -1126,7 +1115,6 @@ GDATA_GD_PHONE_NUMBER_WORK_PAGER
 GDataGDPhoneNumber
 GDataGDPhoneNumberClass
 gdata_gd_phone_number_new
-gdata_gd_phone_number_compare
 gdata_gd_phone_number_get_number
 gdata_gd_phone_number_set_number
 gdata_gd_phone_number_get_uri
@@ -1158,7 +1146,6 @@ GDATA_GD_REMINDER_SMS
 GDataGDReminder
 GDataGDReminderClass
 gdata_gd_reminder_new
-gdata_gd_reminder_compare
 gdata_gd_reminder_get_method
 gdata_gd_reminder_set_method
 gdata_gd_reminder_get_absolute_time
@@ -1773,7 +1760,6 @@ GDataUploadStreamPrivate
 GDataGDName
 GDataGDNameClass
 gdata_gd_name_new
-gdata_gd_name_compare
 gdata_gd_name_get_given_name
 gdata_gd_name_set_given_name
 gdata_gd_name_get_additional_name
@@ -1876,7 +1862,6 @@ GDATA_GCONTACT_WEBSITE_FTP
 GDataGContactWebsite
 GDataGContactWebsiteClass
 gdata_gcontact_website_new
-gdata_gcontact_website_compare
 gdata_gcontact_website_get_uri
 gdata_gcontact_website_set_uri
 gdata_gcontact_website_get_relation_type
@@ -1932,7 +1917,6 @@ GDATA_GCONTACT_CALENDAR_FREE_BUSY
 GDataGContactCalendar
 GDataGContactCalendarClass
 gdata_gcontact_calendar_new
-gdata_gcontact_calendar_compare
 gdata_gcontact_calendar_get_uri
 gdata_gcontact_calendar_set_uri
 gdata_gcontact_calendar_get_relation_type
@@ -1963,7 +1947,6 @@ GDATA_GCONTACT_EXTERNAL_ID_ORGANIZATION
 GDataGContactExternalID
 GDataGContactExternalIDClass
 gdata_gcontact_external_id_new
-gdata_gcontact_external_id_compare
 gdata_gcontact_external_id_get_value
 gdata_gcontact_external_id_set_value
 gdata_gcontact_external_id_get_relation_type
@@ -1988,7 +1971,6 @@ GDataGContactExternalIDPrivate
 GDataGContactLanguage
 GDataGContactLanguageClass
 gdata_gcontact_language_new
-gdata_gcontact_language_compare
 gdata_gcontact_language_get_code
 gdata_gcontact_language_set_code
 gdata_gcontact_language_get_label
@@ -2043,3 +2025,18 @@ GDATA_TYPE_APP_CATEGORIES
 <SUBSECTION Private>
 GDataAPPCategoriesPrivate
 </SECTION>
+
+<SECTION>
+<FILE>gdata-comparable</FILE>
+<TITLE>GDataComparable</TITLE>
+GDataComparable
+GDataComparableIface
+gdata_comparable_compare
+<SUBSECTION Standard>
+gdata_comparable_get_type
+GDATA_COMPARABLE
+GDATA_COMPARABLE_CLASS
+GDATA_COMPARABLE_GET_IFACE
+GDATA_IS_COMPARABLE
+GDATA_TYPE_COMPARABLE
+</SECTION>
diff --git a/gdata/atom/gdata-author.c b/gdata/atom/gdata-author.c
index f8346a5..e5651c1 100644
--- a/gdata/atom/gdata-author.c
+++ b/gdata/atom/gdata-author.c
@@ -35,7 +35,9 @@
 #include "gdata-author.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_author_comparable_init (GDataComparableIface *iface);
 static void gdata_author_finalize (GObject *object);
 static void gdata_author_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_author_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -55,7 +57,8 @@ enum {
 	PROP_EMAIL_ADDRESS
 };
 
-G_DEFINE_TYPE (GDataAuthor, gdata_author, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataAuthor, gdata_author, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_author_comparable_init))
 
 static void
 gdata_author_class_init (GDataAuthorClass *klass)
@@ -123,6 +126,18 @@ gdata_author_class_init (GDataAuthorClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	return g_strcmp0 (((GDataAuthor*) self)->priv->name, ((GDataAuthor*) other)->priv->name);
+}
+
+static void
+gdata_author_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_author_init (GDataAuthor *self)
 {
@@ -247,38 +262,6 @@ gdata_author_new (const gchar *name, const gchar *uri, const gchar *email_addres
 }
 
 /**
- * gdata_author_compare:
- * @a: a #GDataAuthor, or %NULL
- * @b: another #GDataAuthor, or %NULL
- *
- * Compares the two authors in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @name property of the #GDataAuthor<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_author_compare (const GDataAuthor *a, const GDataAuthor *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_AUTHOR (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_AUTHOR (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	return g_strcmp0 (a->priv->name, b->priv->name);
-}
-
-/**
  * gdata_author_get_name:
  * @self: a #GDataAuthor
  *
diff --git a/gdata/atom/gdata-author.h b/gdata/atom/gdata-author.h
index 8580219..2539017 100644
--- a/gdata/atom/gdata-author.h
+++ b/gdata/atom/gdata-author.h
@@ -61,7 +61,6 @@ typedef struct {
 GType gdata_author_get_type (void) G_GNUC_CONST;
 
 GDataAuthor *gdata_author_new (const gchar *name, const gchar *uri, const gchar *email_address) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_author_compare (const GDataAuthor *a, const GDataAuthor *b) G_GNUC_PURE;
 
 const gchar *gdata_author_get_name (GDataAuthor *self) G_GNUC_PURE;
 void gdata_author_set_name (GDataAuthor *self, const gchar *name);
diff --git a/gdata/atom/gdata-category.c b/gdata/atom/gdata-category.c
index 3a32cee..75f6198 100644
--- a/gdata/atom/gdata-category.c
+++ b/gdata/atom/gdata-category.c
@@ -35,7 +35,9 @@
 #include "gdata-category.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_category_comparable_init (GDataComparableIface *iface);
 static void gdata_category_finalize (GObject *object);
 static void gdata_category_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_category_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -54,7 +56,8 @@ enum {
 	PROP_LABEL
 };
 
-G_DEFINE_TYPE (GDataCategory, gdata_category, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataCategory, gdata_category, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_category_comparable_init))
 
 static void
 gdata_category_class_init (GDataCategoryClass *klass)
@@ -124,6 +127,18 @@ gdata_category_class_init (GDataCategoryClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	return g_strcmp0 (((GDataCategory*) self)->priv->term, ((GDataCategory*) other)->priv->term);
+}
+
+static void
+gdata_category_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_category_init (GDataCategory *self)
 {
@@ -239,38 +254,6 @@ gdata_category_new (const gchar *term, const gchar *scheme, const gchar *label)
 }
 
 /**
- * gdata_category_compare:
- * @a: a #GDataCategory, or %NULL
- * @b: another #GDataCategory, or %NULL
- *
- * Compares the two categories in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @term property of the #GDataCategory<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_category_compare (const GDataCategory *a, const GDataCategory *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_CATEGORY (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_CATEGORY (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	return g_strcmp0 (a->priv->term, b->priv->term);
-}
-
-/**
  * gdata_category_get_term:
  * @self: a #GDataCategory
  *
diff --git a/gdata/atom/gdata-category.h b/gdata/atom/gdata-category.h
index 48cbdb6..bae452f 100644
--- a/gdata/atom/gdata-category.h
+++ b/gdata/atom/gdata-category.h
@@ -61,7 +61,6 @@ typedef struct {
 GType gdata_category_get_type (void) G_GNUC_CONST;
 
 GDataCategory *gdata_category_new (const gchar *term, const gchar *scheme, const gchar *label) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_category_compare (const GDataCategory *a, const GDataCategory *b) G_GNUC_PURE;
 
 const gchar *gdata_category_get_term (GDataCategory *self) G_GNUC_PURE;
 void gdata_category_set_term (GDataCategory *self, const gchar *term);
diff --git a/gdata/atom/gdata-generator.c b/gdata/atom/gdata-generator.c
index 7fc7bdb..f5090b3 100644
--- a/gdata/atom/gdata-generator.c
+++ b/gdata/atom/gdata-generator.c
@@ -33,7 +33,9 @@
 #include "gdata-generator.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_generator_comparable_init (GDataComparableIface *iface);
 static void gdata_generator_finalize (GObject *object);
 static void gdata_generator_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
@@ -51,7 +53,8 @@ enum {
 	PROP_VERSION
 };
 
-G_DEFINE_TYPE (GDataGenerator, gdata_generator, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGenerator, gdata_generator, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_generator_comparable_init))
 
 static void
 gdata_generator_class_init (GDataGeneratorClass *klass)
@@ -120,6 +123,18 @@ gdata_generator_class_init (GDataGeneratorClass *klass)
 	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	return g_strcmp0 (((GDataGenerator*) self)->priv->name, ((GDataGenerator*) other)->priv->name);
+}
+
+static void
+gdata_generator_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_generator_init (GDataGenerator *self)
 {
@@ -191,38 +206,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 }
 
 /**
- * gdata_generator_compare:
- * @a: a #GDataGenerator, or %NULL
- * @b: another #GDataGenerator, or %NULL
- *
- * Compares the two generators in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @name property of the #GDataGenerator<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_generator_compare (const GDataGenerator *a, const GDataGenerator *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GENERATOR (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GENERATOR (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	return g_strcmp0 (a->priv->name, b->priv->name);
-}
-
-/**
  * gdata_generator_get_name:
  * @self: a #GDataGenerator
  *
diff --git a/gdata/atom/gdata-generator.h b/gdata/atom/gdata-generator.h
index 057abea..e796b7e 100644
--- a/gdata/atom/gdata-generator.h
+++ b/gdata/atom/gdata-generator.h
@@ -60,8 +60,6 @@ typedef struct {
 
 GType gdata_generator_get_type (void) G_GNUC_CONST;
 
-gint gdata_generator_compare (const GDataGenerator *a, const GDataGenerator *b) G_GNUC_PURE;
-
 const gchar *gdata_generator_get_name (GDataGenerator *self) G_GNUC_PURE;
 const gchar *gdata_generator_get_uri (GDataGenerator *self) G_GNUC_PURE;
 const gchar *gdata_generator_get_version (GDataGenerator *self) G_GNUC_PURE;
diff --git a/gdata/atom/gdata-link.c b/gdata/atom/gdata-link.c
index 85b91d0..581ffe8 100644
--- a/gdata/atom/gdata-link.c
+++ b/gdata/atom/gdata-link.c
@@ -36,7 +36,9 @@
 #include "gdata-link.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_link_comparable_init (GDataComparableIface *iface);
 static void gdata_link_finalize (GObject *object);
 static void gdata_link_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_link_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -61,7 +63,8 @@ enum {
 	PROP_LENGTH
 };
 
-G_DEFINE_TYPE (GDataLink, gdata_link, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataLink, gdata_link, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_link_comparable_init))
 
 static void
 gdata_link_class_init (GDataLinkClass *klass)
@@ -177,6 +180,22 @@ gdata_link_class_init (GDataLinkClass *klass)
 	                                                   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataLinkPrivate *a = ((GDataLink*) self)->priv, *b = ((GDataLink*) other)->priv;
+
+	if (g_strcmp0 (a->uri, b->uri) == 0 && g_strcmp0 (a->relation_type, b->relation_type) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_link_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_link_init (GDataLink *self)
 {
@@ -355,40 +374,6 @@ gdata_link_new (const gchar *uri, const gchar *relation_type)
 }
 
 /**
- * gdata_link_compare:
- * @a: a #GDataLink, or %NULL
- * @b: another #GDataLink, or %NULL
- *
- * Compares the two links in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @uri property of the #GDataLink<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_link_compare (const GDataLink *a, const GDataLink *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_LINK (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_LINK (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	if (g_strcmp0 (a->priv->uri, b->priv->uri) == 0 && g_strcmp0 (a->priv->relation_type, b->priv->relation_type) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_link_get_uri:
  * @self: a #GDataLink
  *
diff --git a/gdata/atom/gdata-link.h b/gdata/atom/gdata-link.h
index 10df3ce..067af88 100644
--- a/gdata/atom/gdata-link.h
+++ b/gdata/atom/gdata-link.h
@@ -146,7 +146,6 @@ typedef struct {
 GType gdata_link_get_type (void) G_GNUC_CONST;
 
 GDataLink *gdata_link_new (const gchar *uri, const gchar *relation_type) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_link_compare (const GDataLink *a, const GDataLink *b) G_GNUC_PURE;
 
 const gchar *gdata_link_get_uri (GDataLink *self) G_GNUC_PURE;
 void gdata_link_set_uri (GDataLink *self, const gchar *uri);
diff --git a/gdata/gcontact/gdata-gcontact-calendar.c b/gdata/gcontact/gdata-gcontact-calendar.c
index 1cb6c20..f035803 100644
--- a/gdata/gcontact/gdata-gcontact-calendar.c
+++ b/gdata/gcontact/gdata-gcontact-calendar.c
@@ -35,7 +35,9 @@
 #include "gdata-gcontact-calendar.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gcontact_calendar_comparable_init (GDataComparableIface *iface);
 static void gdata_gcontact_calendar_finalize (GObject *object);
 static void gdata_gcontact_calendar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gcontact_calendar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -57,7 +59,8 @@ enum {
 	PROP_IS_PRIMARY
 };
 
-G_DEFINE_TYPE (GDataGContactCalendar, gdata_gcontact_calendar, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGContactCalendar, gdata_gcontact_calendar, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gcontact_calendar_comparable_init))
 
 static void
 gdata_gcontact_calendar_class_init (GDataGContactCalendarClass *klass)
@@ -143,6 +146,22 @@ gdata_gcontact_calendar_class_init (GDataGContactCalendarClass *klass)
 	                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGContactCalendarPrivate *a = ((GDataGContactCalendar*) self)->priv, *b = ((GDataGContactCalendar*) other)->priv;
+
+	if (g_strcmp0 (a->uri, b->uri) == 0 && g_strcmp0 (a->relation_type, b->relation_type) == 0 && g_strcmp0 (a->label, b->label) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gcontact_calendar_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gcontact_calendar_init (GDataGContactCalendar *self)
 {
@@ -306,43 +325,6 @@ gdata_gcontact_calendar_new (const gchar *uri, const gchar *relation_type, const
 }
 
 /**
- * gdata_gcontact_calendar_compare:
- * @a: a #GDataGContactCalendar, or %NULL
- * @b: another #GDataGContactCalendar, or %NULL
- *
- * Compares the two calendars in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @uri, @relation_type and @label properties of the #GDataGContactCalendar<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.7.0
- **/
-gint
-gdata_gcontact_calendar_compare (const GDataGContactCalendar *a, const GDataGContactCalendar *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GCONTACT_CALENDAR (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GCONTACT_CALENDAR (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->uri, b->priv->uri) == 0 &&
-	    g_strcmp0 (a->priv->relation_type, b->priv->relation_type) == 0 &&
-	    g_strcmp0 (a->priv->label, b->priv->label) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gcontact_calendar_get_uri:
  * @self: a #GDataGContactCalendar
  *
diff --git a/gdata/gcontact/gdata-gcontact-calendar.h b/gdata/gcontact/gdata-gcontact-calendar.h
index ac7caaa..935a7f6 100644
--- a/gdata/gcontact/gdata-gcontact-calendar.h
+++ b/gdata/gcontact/gdata-gcontact-calendar.h
@@ -100,7 +100,6 @@ GType gdata_gcontact_calendar_get_type (void) G_GNUC_CONST;
 
 GDataGContactCalendar *gdata_gcontact_calendar_new (const gchar *uri, const gchar *relation_type,
                                                     const gchar *label, gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gcontact_calendar_compare (const GDataGContactCalendar *a, const GDataGContactCalendar *b) G_GNUC_PURE;
 
 const gchar *gdata_gcontact_calendar_get_uri (GDataGContactCalendar *self) G_GNUC_PURE;
 void gdata_gcontact_calendar_set_uri (GDataGContactCalendar *self, const gchar *uri);
diff --git a/gdata/gcontact/gdata-gcontact-external-id.c b/gdata/gcontact/gdata-gcontact-external-id.c
index e54c75e..8c4f707 100644
--- a/gdata/gcontact/gdata-gcontact-external-id.c
+++ b/gdata/gcontact/gdata-gcontact-external-id.c
@@ -35,7 +35,9 @@
 #include "gdata-gcontact-external-id.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gcontact_external_id_comparable_init (GDataComparableIface *iface);
 static void gdata_gcontact_external_id_finalize (GObject *object);
 static void gdata_gcontact_external_id_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gcontact_external_id_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -55,7 +57,8 @@ enum {
 	PROP_LABEL
 };
 
-G_DEFINE_TYPE (GDataGContactExternalID, gdata_gcontact_external_id, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGContactExternalID, gdata_gcontact_external_id, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gcontact_external_id_comparable_init))
 
 static void
 gdata_gcontact_external_id_class_init (GDataGContactExternalIDClass *klass)
@@ -125,6 +128,22 @@ gdata_gcontact_external_id_class_init (GDataGContactExternalIDClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGContactExternalIDPrivate *a = ((GDataGContactExternalID*) self)->priv, *b = ((GDataGContactExternalID*) other)->priv;
+
+	if (g_strcmp0 (a->value, b->value) == 0 && g_strcmp0 (a->relation_type, b->relation_type) == 0 && g_strcmp0 (a->label, b->label) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gcontact_external_id_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gcontact_external_id_init (GDataGContactExternalID *self)
 {
@@ -269,44 +288,6 @@ gdata_gcontact_external_id_new (const gchar *value, const gchar *relation_type,
 }
 
 /**
- * gdata_gcontact_external_id_compare:
- * @a: a #GDataGContactExternalID, or %NULL
- * @b: another #GDataGContactExternalID, or %NULL
- *
- * Compares the two external IDs in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @value, @relation_type and @label properties of
- * the #GDataGContactExternalID<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.7.0
- **/
-gint
-gdata_gcontact_external_id_compare (const GDataGContactExternalID *a, const GDataGContactExternalID *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GCONTACT_EXTERNAL_ID (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GCONTACT_EXTERNAL_ID (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->value, b->priv->value) == 0 &&
-	    g_strcmp0 (a->priv->relation_type, b->priv->relation_type) == 0 &&
-	    g_strcmp0 (a->priv->label, b->priv->label) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gcontact_external_id_get_value:
  * @self: a #GDataGContactExternalID
  *
diff --git a/gdata/gcontact/gdata-gcontact-external-id.h b/gdata/gcontact/gdata-gcontact-external-id.h
index 7146f47..d5b2a7c 100644
--- a/gdata/gcontact/gdata-gcontact-external-id.h
+++ b/gdata/gcontact/gdata-gcontact-external-id.h
@@ -112,7 +112,6 @@ GType gdata_gcontact_external_id_get_type (void) G_GNUC_CONST;
 
 GDataGContactExternalID *gdata_gcontact_external_id_new (const gchar *value, const gchar *relation_type,
                                                          const gchar *label) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gcontact_external_id_compare (const GDataGContactExternalID *a, const GDataGContactExternalID *b) G_GNUC_PURE;
 
 const gchar *gdata_gcontact_external_id_get_value (GDataGContactExternalID *self) G_GNUC_PURE;
 void gdata_gcontact_external_id_set_value (GDataGContactExternalID *self, const gchar *value);
diff --git a/gdata/gcontact/gdata-gcontact-language.c b/gdata/gcontact/gdata-gcontact-language.c
index 1866c1c..758dd4e 100644
--- a/gdata/gcontact/gdata-gcontact-language.c
+++ b/gdata/gcontact/gdata-gcontact-language.c
@@ -35,7 +35,9 @@
 #include "gdata-gcontact-language.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gcontact_language_comparable_init (GDataComparableIface *iface);
 static void gdata_gcontact_language_finalize (GObject *object);
 static void gdata_gcontact_language_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gcontact_language_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -53,7 +55,8 @@ enum {
 	PROP_LABEL
 };
 
-G_DEFINE_TYPE (GDataGContactLanguage, gdata_gcontact_language, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGContactLanguage, gdata_gcontact_language, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gcontact_language_comparable_init))
 
 static void
 gdata_gcontact_language_class_init (GDataGContactLanguageClass *klass)
@@ -106,6 +109,22 @@ gdata_gcontact_language_class_init (GDataGContactLanguageClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGContactLanguagePrivate *a = ((GDataGContactLanguage*) self)->priv, *b = ((GDataGContactLanguage*) other)->priv;
+
+	if (g_strcmp0 (a->code, b->code) == 0 && g_strcmp0 (a->label, b->label) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gcontact_language_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gcontact_language_init (GDataGContactLanguage *self)
 {
@@ -228,41 +247,6 @@ gdata_gcontact_language_new (const gchar *code, const gchar *label)
 }
 
 /**
- * gdata_gcontact_language_compare:
- * @a: a #GDataGContactLanguage, or %NULL
- * @b: another #GDataGContactLanguage, or %NULL
- *
- * Compares the two languages in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @code and @label properties of the #GDataGContactLanguage<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.7.0
- **/
-gint
-gdata_gcontact_language_compare (const GDataGContactLanguage *a, const GDataGContactLanguage *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GCONTACT_LANGUAGE (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GCONTACT_LANGUAGE (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->code, b->priv->code) == 0 && g_strcmp0 (a->priv->label, b->priv->label) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gcontact_language_get_code:
  * @self: a #GDataGContactLanguage
  *
diff --git a/gdata/gcontact/gdata-gcontact-language.h b/gdata/gcontact/gdata-gcontact-language.h
index 9995f52..397852d 100644
--- a/gdata/gcontact/gdata-gcontact-language.h
+++ b/gdata/gcontact/gdata-gcontact-language.h
@@ -63,7 +63,6 @@ typedef struct {
 GType gdata_gcontact_language_get_type (void) G_GNUC_CONST;
 
 GDataGContactLanguage *gdata_gcontact_language_new (const gchar *code, const gchar *label) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gcontact_language_compare (const GDataGContactLanguage *a, const GDataGContactLanguage *b) G_GNUC_PURE;
 
 const gchar *gdata_gcontact_language_get_code (GDataGContactLanguage *self) G_GNUC_PURE;
 void gdata_gcontact_language_set_code (GDataGContactLanguage *self, const gchar *code);
diff --git a/gdata/gcontact/gdata-gcontact-website.c b/gdata/gcontact/gdata-gcontact-website.c
index d4cb0b7..1e089e3 100644
--- a/gdata/gcontact/gdata-gcontact-website.c
+++ b/gdata/gcontact/gdata-gcontact-website.c
@@ -35,7 +35,9 @@
 #include "gdata-gcontact-website.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gcontact_website_comparable_init (GDataComparableIface *iface);
 static void gdata_gcontact_website_finalize (GObject *object);
 static void gdata_gcontact_website_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gcontact_website_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -57,7 +59,8 @@ enum {
 	PROP_IS_PRIMARY
 };
 
-G_DEFINE_TYPE (GDataGContactWebsite, gdata_gcontact_website, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGContactWebsite, gdata_gcontact_website, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gcontact_website_comparable_init))
 
 static void
 gdata_gcontact_website_class_init (GDataGContactWebsiteClass *klass)
@@ -142,6 +145,22 @@ gdata_gcontact_website_class_init (GDataGContactWebsiteClass *klass)
 	                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGContactWebsitePrivate *a = ((GDataGContactWebsite*) self)->priv, *b = ((GDataGContactWebsite*) other)->priv;
+
+	if (g_strcmp0 (a->uri, b->uri) == 0 && g_strcmp0 (a->relation_type, b->relation_type) == 0 && g_strcmp0 (a->label, b->label) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gcontact_website_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gcontact_website_init (GDataGContactWebsite *self)
 {
@@ -289,43 +308,6 @@ gdata_gcontact_website_new (const gchar *uri, const gchar *relation_type, const
 }
 
 /**
- * gdata_gcontact_website_compare:
- * @a: a #GDataGContactWebsite, or %NULL
- * @b: another #GDataGContactWebsite, or %NULL
- *
- * Compares the two websites in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @uri, @relation_type and @label properties of the #GDataGContactWebsite<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.7.0
- **/
-gint
-gdata_gcontact_website_compare (const GDataGContactWebsite *a, const GDataGContactWebsite *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GCONTACT_WEBSITE (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GCONTACT_WEBSITE (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->uri, b->priv->uri) == 0 &&
-	    g_strcmp0 (a->priv->relation_type, b->priv->relation_type) == 0 &&
-	    g_strcmp0 (a->priv->label, b->priv->label) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gcontact_website_get_uri:
  * @self: a #GDataGContactWebsite
  *
diff --git a/gdata/gcontact/gdata-gcontact-website.h b/gdata/gcontact/gdata-gcontact-website.h
index bfdc225..de3a372 100644
--- a/gdata/gcontact/gdata-gcontact-website.h
+++ b/gdata/gcontact/gdata-gcontact-website.h
@@ -148,7 +148,6 @@ GType gdata_gcontact_website_get_type (void) G_GNUC_CONST;
 
 GDataGContactWebsite *gdata_gcontact_website_new (const gchar *uri, const gchar *relation_type,
                                                   const gchar *label, gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gcontact_website_compare (const GDataGContactWebsite *a, const GDataGContactWebsite *b) G_GNUC_PURE;
 
 const gchar *gdata_gcontact_website_get_uri (GDataGContactWebsite *self) G_GNUC_PURE;
 void gdata_gcontact_website_set_uri (GDataGContactWebsite *self, const gchar *uri);
diff --git a/gdata/gd/gdata-gd-email-address.c b/gdata/gd/gdata-gd-email-address.c
index 8c1f49f..22b7a88 100644
--- a/gdata/gd/gdata-gd-email-address.c
+++ b/gdata/gd/gdata-gd-email-address.c
@@ -35,7 +35,9 @@
 #include "gdata-gd-email-address.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_email_address_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_email_address_finalize (GObject *object);
 static void gdata_gd_email_address_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_email_address_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -59,7 +61,8 @@ enum {
 	PROP_DISPLAY_NAME
 };
 
-G_DEFINE_TYPE (GDataGDEmailAddress, gdata_gd_email_address, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDEmailAddress, gdata_gd_email_address, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_email_address_comparable_init))
 
 static void
 gdata_gd_email_address_class_init (GDataGDEmailAddressClass *klass)
@@ -160,6 +163,18 @@ gdata_gd_email_address_class_init (GDataGDEmailAddressClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	return g_strcmp0 (((GDataGDEmailAddress*) self)->priv->address, ((GDataGDEmailAddress*) other)->priv->address);
+}
+
+static void
+gdata_gd_email_address_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_email_address_init (GDataGDEmailAddress *self)
 {
@@ -318,38 +333,6 @@ gdata_gd_email_address_new (const gchar *address, const gchar *relation_type, co
 }
 
 /**
- * gdata_gd_email_address_compare:
- * @a: a #GDataGDEmailAddress, or %NULL
- * @b: another #GDataGDEmailAddress, or %NULL
- *
- * Compares the two e-mail addresses in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @address property of the #GDataGDEmailAddress<!-- -->es.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_email_address_compare (const GDataGDEmailAddress *a, const GDataGDEmailAddress *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_EMAIL_ADDRESS (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_EMAIL_ADDRESS (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	return g_strcmp0 (a->priv->address, b->priv->address);
-}
-
-/**
  * gdata_gd_email_address_get_address:
  * @self: a #GDataGDEmailAddress
  *
diff --git a/gdata/gd/gdata-gd-email-address.h b/gdata/gd/gdata-gd-email-address.h
index 401f379..dcce21f 100644
--- a/gdata/gd/gdata-gd-email-address.h
+++ b/gdata/gd/gdata-gd-email-address.h
@@ -91,7 +91,6 @@ GType gdata_gd_email_address_get_type (void) G_GNUC_CONST;
 
 GDataGDEmailAddress *gdata_gd_email_address_new (const gchar *address, const gchar *relation_type,
                                                  const gchar *label, gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_email_address_compare (const GDataGDEmailAddress *a, const GDataGDEmailAddress *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_email_address_get_address (GDataGDEmailAddress *self) G_GNUC_PURE;
 void gdata_gd_email_address_set_address (GDataGDEmailAddress *self, const gchar *address);
diff --git a/gdata/gd/gdata-gd-im-address.c b/gdata/gd/gdata-gd-im-address.c
index a47c52c..1ada4a7 100644
--- a/gdata/gd/gdata-gd-im-address.c
+++ b/gdata/gd/gdata-gd-im-address.c
@@ -35,7 +35,9 @@
 #include "gdata-gd-im-address.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_im_address_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_im_address_finalize (GObject *object);
 static void gdata_gd_im_address_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_im_address_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -59,7 +61,8 @@ enum {
 	PROP_IS_PRIMARY
 };
 
-G_DEFINE_TYPE (GDataGDIMAddress, gdata_gd_im_address, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDIMAddress, gdata_gd_im_address, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_im_address_comparable_init))
 
 static void
 gdata_gd_im_address_class_init (GDataGDIMAddressClass *klass)
@@ -160,6 +163,22 @@ gdata_gd_im_address_class_init (GDataGDIMAddressClass *klass)
 	                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGDIMAddressPrivate *a = ((GDataGDIMAddress*) self)->priv, *b = ((GDataGDIMAddress*) other)->priv;
+
+	if (g_strcmp0 (a->address, b->address) == 0 && g_strcmp0 (a->protocol, b->protocol) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gd_im_address_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_im_address_init (GDataGDIMAddress *self)
 {
@@ -322,41 +341,6 @@ gdata_gd_im_address_new (const gchar *address, const gchar *protocol, const gcha
 }
 
 /**
- * gdata_gd_im_address_compare:
- * @a: a #GDataGDIMAddress, or %NULL
- * @b: another #GDataGDIMAddress, or %NULL
- *
- * Compares the two IM addresses in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @address and @protocol properties of the #GDataGDIMAddress<!-- -->es.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_im_address_compare (const GDataGDIMAddress *a, const GDataGDIMAddress *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_IM_ADDRESS (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_IM_ADDRESS (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->address, b->priv->address) == 0 && g_strcmp0 (a->priv->protocol, b->priv->protocol) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gd_im_address_get_address:
  * @self: a #GDataGDIMAddress
  *
diff --git a/gdata/gd/gdata-gd-im-address.h b/gdata/gd/gdata-gd-im-address.h
index b87485e..8f0cf0d 100644
--- a/gdata/gd/gdata-gd-im-address.h
+++ b/gdata/gd/gdata-gd-im-address.h
@@ -172,7 +172,6 @@ GType gdata_gd_im_address_get_type (void) G_GNUC_CONST;
 
 GDataGDIMAddress *gdata_gd_im_address_new (const gchar *address, const gchar *protocol, const gchar *relation_type, const gchar *label,
                                            gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_im_address_compare (const GDataGDIMAddress *a, const GDataGDIMAddress *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_im_address_get_address (GDataGDIMAddress *self) G_GNUC_PURE;
 void gdata_gd_im_address_set_address (GDataGDIMAddress *self, const gchar *address);
diff --git a/gdata/gd/gdata-gd-name.c b/gdata/gd/gdata-gd-name.c
index b400279..fafc49a 100644
--- a/gdata/gd/gdata-gd-name.c
+++ b/gdata/gd/gdata-gd-name.c
@@ -45,7 +45,9 @@
 #include "gdata-gd-name.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_name_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_name_finalize (GObject *object);
 static void gdata_gd_name_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_name_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -71,7 +73,8 @@ enum {
 	PROP_FULL_NAME
 };
 
-G_DEFINE_TYPE (GDataGDName, gdata_gd_name, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDName, gdata_gd_name, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_name_comparable_init))
 
 static void
 gdata_gd_name_class_init (GDataGDNameClass *klass)
@@ -189,6 +192,23 @@ gdata_gd_name_class_init (GDataGDNameClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGDNamePrivate *a = ((GDataGDName*) self)->priv, *b = ((GDataGDName*) other)->priv;
+
+	if (g_strcmp0 (a->given_name, b->given_name) == 0 && g_strcmp0 (a->additional_name, b->additional_name) == 0 &&
+	    g_strcmp0 (a->family_name, b->family_name) == 0 && g_strcmp0 (a->prefix, b->prefix) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gd_name_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_name_init (GDataGDName *self)
 {
@@ -338,42 +358,6 @@ gdata_gd_name_new (const gchar *given_name, const gchar *family_name)
 }
 
 /**
- * gdata_gd_name_compare:
- * @a: a #GDataGDName, or %NULL
- * @b: another #GDataGDName, or %NULL
- *
- * Compares the two names in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @given_name, @additional_name and @family_name properties of the
- * #GDataGDName<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.5.0
- **/
-gint
-gdata_gd_name_compare (const GDataGDName *a, const GDataGDName *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_NAME (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_NAME (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	if (g_strcmp0 (a->priv->given_name, b->priv->given_name) == 0 && g_strcmp0 (a->priv->additional_name, b->priv->additional_name) == 0 &&
-	    g_strcmp0 (a->priv->family_name, b->priv->family_name) == 0 && g_strcmp0 (a->priv->prefix, b->priv->prefix) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gd_name_get_given_name:
  * @self: a #GDataGDName
  *
diff --git a/gdata/gd/gdata-gd-name.h b/gdata/gd/gdata-gd-name.h
index f54c08c..7eac315 100644
--- a/gdata/gd/gdata-gd-name.h
+++ b/gdata/gd/gdata-gd-name.h
@@ -63,7 +63,6 @@ typedef struct {
 GType gdata_gd_name_get_type (void) G_GNUC_CONST;
 
 GDataGDName *gdata_gd_name_new (const gchar *given_name, const gchar *family_name) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_name_compare (const GDataGDName *a, const GDataGDName *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_name_get_given_name (GDataGDName *self) G_GNUC_PURE;
 void gdata_gd_name_set_given_name (GDataGDName *self, const gchar *given_name);
diff --git a/gdata/gd/gdata-gd-organization.c b/gdata/gd/gdata-gd-organization.c
index 0abb5de..af82469 100644
--- a/gdata/gd/gdata-gd-organization.c
+++ b/gdata/gd/gdata-gd-organization.c
@@ -37,7 +37,9 @@
 #include "gdata-parser.h"
 #include "gdata-gd-where.h"
 #include "gdata-private.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_organization_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_organization_dispose (GObject *object);
 static void gdata_gd_organization_finalize (GObject *object);
 static void gdata_gd_organization_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
@@ -72,7 +74,8 @@ enum {
 	PROP_LOCATION
 };
 
-G_DEFINE_TYPE (GDataGDOrganization, gdata_gd_organization, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDOrganization, gdata_gd_organization, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_organization_comparable_init))
 
 static void
 gdata_gd_organization_class_init (GDataGDOrganizationClass *klass)
@@ -241,6 +244,22 @@ gdata_gd_organization_class_init (GDataGDOrganizationClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGDOrganizationPrivate *a = ((GDataGDOrganization*) self)->priv, *b = ((GDataGDOrganization*) other)->priv;
+
+	if (g_strcmp0 (a->name, b->name) == 0 && g_strcmp0 (a->title, b->title) == 0 && g_strcmp0 (a->department, b->department) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gd_organization_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_organization_init (GDataGDOrganization *self)
 {
@@ -465,41 +484,6 @@ gdata_gd_organization_new (const gchar *name, const gchar *title, const gchar *r
 }
 
 /**
- * gdata_gd_organization_compare:
- * @a: a #GDataGDOrganization, or %NULL
- * @b: another #GDataGDOrganization, or %NULL
- *
- * Compares the two organizations in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @name property of the #GDataGDOrganization<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_organization_compare (const GDataGDOrganization *a, const GDataGDOrganization *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_ORGANIZATION (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_ORGANIZATION (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	if (g_strcmp0 (a->priv->name, b->priv->name) == 0 && g_strcmp0 (a->priv->title, b->priv->title) == 0 &&
-	    g_strcmp0 (a->priv->department, b->priv->department) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gd_organization_get_name:
  * @self: a #GDataGDOrganization
  *
diff --git a/gdata/gd/gdata-gd-organization.h b/gdata/gd/gdata-gd-organization.h
index 1707245..20341f4 100644
--- a/gdata/gd/gdata-gd-organization.h
+++ b/gdata/gd/gdata-gd-organization.h
@@ -83,7 +83,6 @@ GType gdata_gd_organization_get_type (void) G_GNUC_CONST;
 
 GDataGDOrganization *gdata_gd_organization_new (const gchar *name, const gchar *title, const gchar *relation_type,
                                                 const gchar *label, gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_organization_compare (const GDataGDOrganization *a, const GDataGDOrganization *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_organization_get_name (GDataGDOrganization *self) G_GNUC_PURE;
 void gdata_gd_organization_set_name (GDataGDOrganization *self, const gchar *name);
diff --git a/gdata/gd/gdata-gd-phone-number.c b/gdata/gd/gdata-gd-phone-number.c
index 55a32c0..fad36ac 100644
--- a/gdata/gd/gdata-gd-phone-number.c
+++ b/gdata/gd/gdata-gd-phone-number.c
@@ -36,7 +36,9 @@
 #include "gdata-gd-phone-number.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_phone_number_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_phone_number_finalize (GObject *object);
 static void gdata_gd_phone_number_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_phone_number_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -62,7 +64,8 @@ enum {
 	PROP_IS_PRIMARY
 };
 
-G_DEFINE_TYPE (GDataGDPhoneNumber, gdata_gd_phone_number, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDPhoneNumber, gdata_gd_phone_number, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_phone_number_comparable_init))
 
 static void
 gdata_gd_phone_number_class_init (GDataGDPhoneNumberClass *klass)
@@ -165,6 +168,18 @@ gdata_gd_phone_number_class_init (GDataGDPhoneNumberClass *klass)
 	                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	return g_strcmp0 (((GDataGDPhoneNumber*) self)->priv->number, ((GDataGDPhoneNumber*) other)->priv->number);
+}
+
+static void
+gdata_gd_phone_number_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_phone_number_init (GDataGDPhoneNumber *self)
 {
@@ -342,38 +357,6 @@ gdata_gd_phone_number_new (const gchar *number, const gchar *relation_type, cons
 }
 
 /**
- * gdata_gd_phone_number_compare:
- * @a: a #GDataGDPhoneNumber, or %NULL
- * @b: another #GDataGDPhoneNumber, or %NULL
- *
- * Compares the two phone numbers in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @number property of the #GDataGDPhoneNumber<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_phone_number_compare (const GDataGDPhoneNumber *a, const GDataGDPhoneNumber *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_PHONE_NUMBER (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_PHONE_NUMBER (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	return g_strcmp0 (a->priv->number, b->priv->number);
-}
-
-/**
  * gdata_gd_phone_number_get_number:
  * @self: a #GDataGDPhoneNumber
  *
diff --git a/gdata/gd/gdata-gd-phone-number.h b/gdata/gd/gdata-gd-phone-number.h
index ae786bd..5f6a15b 100644
--- a/gdata/gd/gdata-gd-phone-number.h
+++ b/gdata/gd/gdata-gd-phone-number.h
@@ -244,7 +244,6 @@ GType gdata_gd_phone_number_get_type (void) G_GNUC_CONST;
 
 GDataGDPhoneNumber *gdata_gd_phone_number_new (const gchar *number, const gchar *relation_type, const gchar *label, const gchar *uri,
                                                gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_phone_number_compare (const GDataGDPhoneNumber *a, const GDataGDPhoneNumber *b);
 
 const gchar *gdata_gd_phone_number_get_number (GDataGDPhoneNumber *self) G_GNUC_PURE;
 void gdata_gd_phone_number_set_number (GDataGDPhoneNumber *self, const gchar *number);
diff --git a/gdata/gd/gdata-gd-postal-address.c b/gdata/gd/gdata-gd-postal-address.c
index 98e1410..fce247f 100644
--- a/gdata/gd/gdata-gd-postal-address.c
+++ b/gdata/gd/gdata-gd-postal-address.c
@@ -37,7 +37,9 @@
 #include "gdata-gd-postal-address.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_postal_address_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_postal_address_finalize (GObject *object);
 static void gdata_gd_postal_address_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_postal_address_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -87,7 +89,8 @@ enum {
 	PROP_COUNTRY_CODE
 };
 
-G_DEFINE_TYPE (GDataGDPostalAddress, gdata_gd_postal_address, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDPostalAddress, gdata_gd_postal_address, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_postal_address_comparable_init))
 
 static void
 gdata_gd_postal_address_class_init (GDataGDPostalAddressClass *klass)
@@ -388,6 +391,23 @@ gdata_gd_postal_address_class_init (GDataGDPostalAddressClass *klass)
 	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGDPostalAddressPrivate *a = ((GDataGDPostalAddress*) self)->priv, *b = ((GDataGDPostalAddress*) other)->priv;
+
+	if (g_strcmp0 (a->street, b->street) == 0 && g_strcmp0 (a->po_box, b->po_box) == 0 &&
+	    g_strcmp0 (a->city, b->city) == 0 && g_strcmp0 (a->postcode, b->postcode) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gd_postal_address_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_postal_address_init (GDataGDPostalAddress *self)
 {
@@ -663,42 +683,6 @@ gdata_gd_postal_address_new (const gchar *relation_type, const gchar *label, gbo
 }
 
 /**
- * gdata_gd_postal_address_compare:
- * @a: a #GDataGDPostalAddress, or %NULL
- * @b: another #GDataGDPostalAddress, or %NULL
- *
- * Compares the two postal addresses in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @street, @po_box, @city and @postcode properties of
- * the #GDataGDPostalAddress<!-- -->es.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_postal_address_compare (const GDataGDPostalAddress *a, const GDataGDPostalAddress *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_POSTAL_ADDRESS (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_POSTAL_ADDRESS (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	if (g_strcmp0 (a->priv->street, b->priv->street) == 0 && g_strcmp0 (a->priv->po_box, b->priv->po_box) == 0 &&
-	    g_strcmp0 (a->priv->city, b->priv->city) == 0 && g_strcmp0 (a->priv->postcode, b->priv->postcode) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gd_postal_address_get_address:
  * @self: a #GDataGDPostalAddress
  *
diff --git a/gdata/gd/gdata-gd-postal-address.h b/gdata/gd/gdata-gd-postal-address.h
index 4739461..86ebc70 100644
--- a/gdata/gd/gdata-gd-postal-address.h
+++ b/gdata/gd/gdata-gd-postal-address.h
@@ -145,7 +145,6 @@ GType gdata_gd_postal_address_get_type (void) G_GNUC_CONST;
 
 GDataGDPostalAddress *gdata_gd_postal_address_new (const gchar *relation_type, const gchar *label,
                                                    gboolean is_primary) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_postal_address_compare (const GDataGDPostalAddress *a, const GDataGDPostalAddress *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_postal_address_get_address (GDataGDPostalAddress *self) G_GNUC_PURE;
 void gdata_gd_postal_address_set_address (GDataGDPostalAddress *self, const gchar *address);
diff --git a/gdata/gd/gdata-gd-reminder.c b/gdata/gd/gdata-gd-reminder.c
index c069b62..ecb2bac 100644
--- a/gdata/gd/gdata-gd-reminder.c
+++ b/gdata/gd/gdata-gd-reminder.c
@@ -36,7 +36,9 @@
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
 #include "gdata-types.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_reminder_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_reminder_finalize (GObject *object);
 static void gdata_gd_reminder_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_reminder_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -57,7 +59,8 @@ enum {
 	PROP_RELATIVE_TIME
 };
 
-G_DEFINE_TYPE (GDataGDReminder, gdata_gd_reminder, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDReminder, gdata_gd_reminder, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_reminder_comparable_init))
 
 static void
 gdata_gd_reminder_class_init (GDataGDReminderClass *klass)
@@ -142,6 +145,35 @@ gdata_gd_reminder_class_init (GDataGDReminderClass *klass)
 	                                                   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	gint method_cmp;
+	GDataGDReminder *a = (GDataGDReminder*) self, *b = (GDataGDReminder*) other;
+
+	if (gdata_gd_reminder_is_absolute_time (a) != gdata_gd_reminder_is_absolute_time (b))
+		return 1;
+
+	method_cmp = g_strcmp0 (a->priv->method, b->priv->method);
+	if (gdata_gd_reminder_is_absolute_time (a) == TRUE) {
+		if (method_cmp == 0 &&
+		    a->priv->absolute_time.tv_sec == b->priv->absolute_time.tv_sec &&
+		    a->priv->absolute_time.tv_usec == b->priv->absolute_time.tv_usec)
+			return 0;
+	} else {
+		if (method_cmp == 0 && a->priv->relative_time == b->priv->relative_time)
+			return 0;
+	}
+
+	return method_cmp;
+}
+
+static void
+gdata_gd_reminder_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_reminder_init (GDataGDReminder *self)
 {
@@ -302,55 +334,6 @@ gdata_gd_reminder_new (const gchar *method, const GTimeVal *absolute_time, gint
 }
 
 /**
- * gdata_gd_reminder_compare:
- * @a: a #GDataGDReminder, or %NULL
- * @b: another #GDataGDReminder, or %NULL
- *
- * Compares the two reminders in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis all the properties of the #GDataGDReminder<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_reminder_compare (const GDataGDReminder *a, const GDataGDReminder *b)
-{
-	gint method_cmp;
-
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_REMINDER (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_REMINDER (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (gdata_gd_reminder_is_absolute_time ((GDataGDReminder*) a) != gdata_gd_reminder_is_absolute_time ((GDataGDReminder*) b))
-		return 1;
-
-	method_cmp = g_strcmp0 (a->priv->method, b->priv->method);
-	if (gdata_gd_reminder_is_absolute_time ((GDataGDReminder*) a) == TRUE) {
-		if (method_cmp == 0 &&
-		    a->priv->absolute_time.tv_sec == b->priv->absolute_time.tv_sec &&
-		    a->priv->absolute_time.tv_usec == b->priv->absolute_time.tv_usec)
-			return 0;
-	} else {
-		if (method_cmp == 0 && a->priv->relative_time == b->priv->relative_time)
-			return 0;
-	}
-
-	return method_cmp;
-}
-
-/**
  * gdata_gd_reminder_get_method:
  * @self: a #GDataGDReminder
  *
diff --git a/gdata/gd/gdata-gd-reminder.h b/gdata/gd/gdata-gd-reminder.h
index e9af456..96a39d7 100644
--- a/gdata/gd/gdata-gd-reminder.h
+++ b/gdata/gd/gdata-gd-reminder.h
@@ -91,7 +91,6 @@ GType gdata_gd_reminder_get_type (void) G_GNUC_CONST;
 
 GDataGDReminder *gdata_gd_reminder_new (const gchar *method, const GTimeVal *absolute_time,
                                         gint relative_time) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_reminder_compare (const GDataGDReminder *a, const GDataGDReminder *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_reminder_get_method (GDataGDReminder *self) G_GNUC_PURE;
 void gdata_gd_reminder_set_method (GDataGDReminder *self, const gchar *method);
diff --git a/gdata/gd/gdata-gd-when.c b/gdata/gd/gdata-gd-when.c
index c06eb65..85f729c 100644
--- a/gdata/gd/gdata-gd-when.c
+++ b/gdata/gd/gdata-gd-when.c
@@ -38,7 +38,9 @@
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
 #include "gdata-types.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_when_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_when_dispose (GObject *object);
 static void gdata_gd_when_finalize (GObject *object);
 static void gdata_gd_when_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
@@ -65,7 +67,8 @@ enum {
 	PROP_VALUE_STRING
 };
 
-G_DEFINE_TYPE (GDataGDWhen, gdata_gd_when, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDWhen, gdata_gd_when, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_when_comparable_init))
 
 static void
 gdata_gd_when_class_init (GDataGDWhenClass *klass)
@@ -155,6 +158,29 @@ gdata_gd_when_class_init (GDataGDWhenClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	gint64 start_diff, end_diff;
+	GDataGDWhenPrivate *a = ((GDataGDWhen*) self)->priv, *b = ((GDataGDWhen*) other)->priv;
+
+	if (a->is_date != b->is_date)
+		return CLAMP (b->is_date - a->is_date, -1, 1);
+
+	start_diff = (b->start_time.tv_sec - a->start_time.tv_sec) * 1000000 + (b->start_time.tv_usec - a->start_time.tv_usec);
+	end_diff = (b->end_time.tv_sec - a->end_time.tv_sec) * 1000000 + (b->end_time.tv_usec - a->end_time.tv_usec);
+
+	if (start_diff == 0)
+		return CLAMP (end_diff, -1, 1);
+	return CLAMP (start_diff, -1, 1);
+}
+
+static void
+gdata_gd_when_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_when_init (GDataGDWhen *self)
 {
@@ -379,50 +405,6 @@ gdata_gd_when_new (const GTimeVal *start_time, const GTimeVal *end_time, gboolea
 }
 
 /**
- * gdata_gd_when_compare:
- * @a: a #GDataGDWhen, or %NULL
- * @b: another #GDataGDWhen, or %NULL
- *
- * Compares the two times in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @start_time, @end_time and @is_date properties of the #GDataGDWhen<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_when_compare (const GDataGDWhen *a, const GDataGDWhen *b)
-{
-	gint64 start_diff, end_diff;
-
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_WHEN (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_WHEN (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-	if (a->priv->is_date != b->priv->is_date)
-		return CLAMP (b->priv->is_date - a->priv->is_date, -1, 1);
-
-	start_diff = (b->priv->start_time.tv_sec - a->priv->start_time.tv_sec) * 1000000 +
-	             (b->priv->start_time.tv_usec - a->priv->start_time.tv_usec);
-	end_diff = (b->priv->end_time.tv_sec - a->priv->end_time.tv_sec) * 1000000 +
-	           (b->priv->end_time.tv_usec - a->priv->end_time.tv_usec);
-
-	if (start_diff == 0)
-		return CLAMP (end_diff, -1, 1);
-	return CLAMP (start_diff, -1, 1);
-}
-
-/**
  * gdata_gd_when_get_start_time:
  * @self: a #GDataGDWhen
  * @start_time: return location for the start time
@@ -608,6 +590,6 @@ gdata_gd_when_add_reminder (GDataGDWhen *self, GDataGDReminder *reminder)
 	g_return_if_fail (GDATA_IS_GD_WHEN (self));
 	g_return_if_fail (GDATA_IS_GD_REMINDER (reminder));
 
-	if (g_list_find_custom (self->priv->reminders, reminder, (GCompareFunc) gdata_gd_reminder_compare) == NULL)
+	if (g_list_find_custom (self->priv->reminders, reminder, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->reminders = g_list_append (self->priv->reminders, g_object_ref (reminder));
 }
diff --git a/gdata/gd/gdata-gd-when.h b/gdata/gd/gdata-gd-when.h
index 2c73fb6..8ab33b0 100644
--- a/gdata/gd/gdata-gd-when.h
+++ b/gdata/gd/gdata-gd-when.h
@@ -145,7 +145,6 @@ typedef struct {
 GType gdata_gd_when_get_type (void) G_GNUC_CONST;
 
 GDataGDWhen *gdata_gd_when_new (const GTimeVal *start_time, const GTimeVal *end_time, gboolean is_date) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_when_compare (const GDataGDWhen *a, const GDataGDWhen *b) G_GNUC_PURE;
 
 void gdata_gd_when_get_start_time (GDataGDWhen *self, GTimeVal *start_time);
 void gdata_gd_when_set_start_time (GDataGDWhen *self, const GTimeVal *start_time);
diff --git a/gdata/gd/gdata-gd-where.c b/gdata/gd/gdata-gd-where.c
index 24172f1..0d1124c 100644
--- a/gdata/gd/gdata-gd-where.c
+++ b/gdata/gd/gdata-gd-where.c
@@ -35,7 +35,9 @@
 #include "gdata-gd-where.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_where_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_where_finalize (GObject *object);
 static void gdata_gd_where_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_where_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -57,7 +59,8 @@ enum {
 	PROP_LABEL
 };
 
-G_DEFINE_TYPE (GDataGDWhere, gdata_gd_where, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDWhere, gdata_gd_where, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_where_comparable_init))
 
 static void
 gdata_gd_where_class_init (GDataGDWhereClass *klass)
@@ -129,6 +132,22 @@ gdata_gd_where_class_init (GDataGDWhereClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGDWherePrivate *a = ((GDataGDWhere*) self)->priv, *b = ((GDataGDWhere*) other)->priv;
+
+	if (g_strcmp0 (a->value_string, b->value_string) == 0 && g_strcmp0 (a->label, b->label) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gd_where_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_where_init (GDataGDWhere *self)
 {
@@ -273,41 +292,6 @@ gdata_gd_where_new (const gchar *relation_type, const gchar *value_string, const
 }
 
 /**
- * gdata_gd_where_compare:
- * @a: a #GDataGDWhere, or %NULL
- * @b: another #GDataGDWhere, or %NULL
- *
- * Compares the two places in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @label and @value_string properties of the #GDataGDWhere<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_where_compare (const GDataGDWhere *a, const GDataGDWhere *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_WHERE (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_WHERE (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->value_string, b->priv->value_string) == 0 && g_strcmp0 (a->priv->label, b->priv->label) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gd_where_get_relation_type:
  * @self: a #GDataGDWhere
  *
diff --git a/gdata/gd/gdata-gd-where.h b/gdata/gd/gdata-gd-where.h
index 187f328..00b43ec 100644
--- a/gdata/gd/gdata-gd-where.h
+++ b/gdata/gd/gdata-gd-where.h
@@ -90,7 +90,6 @@ typedef struct {
 GType gdata_gd_where_get_type (void) G_GNUC_CONST;
 
 GDataGDWhere *gdata_gd_where_new (const gchar *relation_type, const gchar *value_string, const gchar *label) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_where_compare (const GDataGDWhere *a, const GDataGDWhere *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_where_get_relation_type (GDataGDWhere *self) G_GNUC_PURE;
 void gdata_gd_where_set_relation_type (GDataGDWhere *self, const gchar *relation_type);
diff --git a/gdata/gd/gdata-gd-who.c b/gdata/gd/gdata-gd-who.c
index 8ccbe55..dbb85cc 100644
--- a/gdata/gd/gdata-gd-who.c
+++ b/gdata/gd/gdata-gd-who.c
@@ -35,7 +35,9 @@
 #include "gdata-gd-who.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-comparable.h"
 
+static void gdata_gd_who_comparable_init (GDataComparableIface *iface);
 static void gdata_gd_who_finalize (GObject *object);
 static void gdata_gd_who_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_gd_who_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
@@ -57,7 +59,8 @@ enum {
 	PROP_EMAIL_ADDRESS
 };
 
-G_DEFINE_TYPE (GDataGDWho, gdata_gd_who, GDATA_TYPE_PARSABLE)
+G_DEFINE_TYPE_WITH_CODE (GDataGDWho, gdata_gd_who, GDATA_TYPE_PARSABLE,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_who_comparable_init))
 
 static void
 gdata_gd_who_class_init (GDataGDWhoClass *klass)
@@ -129,6 +132,22 @@ gdata_gd_who_class_init (GDataGDWhoClass *klass)
 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+static gint
+compare_with (GDataComparable *self, GDataComparable *other)
+{
+	GDataGDWhoPrivate *a = ((GDataGDWho*) self)->priv, *b = ((GDataGDWho*) other)->priv;
+
+	if (g_strcmp0 (a->value_string, b->value_string) == 0 && g_strcmp0 (a->email_address, b->email_address) == 0)
+		return 0;
+	return 1;
+}
+
+static void
+gdata_gd_who_comparable_init (GDataComparableIface *iface)
+{
+	iface->compare_with = compare_with;
+}
+
 static void
 gdata_gd_who_init (GDataGDWho *self)
 {
@@ -279,41 +298,6 @@ gdata_gd_who_new (const gchar *relation_type, const gchar *value_string, const g
 }
 
 /**
- * gdata_gd_who_compare:
- * @a: a #GDataGDWho, or %NULL
- * @b: another #GDataGDWho, or %NULL
- *
- * Compares the two people in a strcmp() fashion. %NULL values are handled gracefully, with
- * <code class="literal">0</code> returned if both @a and @b are %NULL, <code class="literal">-1</code> if @a is %NULL
- * and <code class="literal">1</code> if @b is %NULL.
- *
- * The comparison of non-%NULL values is done on the basis of the @email and @value_string properties of the #GDataGDWho<!-- -->s.
- *
- * Return value: <code class="literal">0</code> if @a equals @b, <code class="literal">-1</code> or <code class="literal">1</code> as
- * appropriate otherwise
- *
- * Since: 0.4.0
- **/
-gint
-gdata_gd_who_compare (const GDataGDWho *a, const GDataGDWho *b)
-{
-	g_return_val_if_fail (a == NULL || GDATA_IS_GD_WHO (a), 0);
-	g_return_val_if_fail (b == NULL || GDATA_IS_GD_WHO (b), 0);
-
-	if (a == NULL && b != NULL)
-		return -1;
-	else if (a != NULL && b == NULL)
-		return 1;
-
-	if (a == b)
-		return 0;
-
-	if (g_strcmp0 (a->priv->value_string, b->priv->value_string) == 0 && g_strcmp0 (a->priv->email_address, b->priv->email_address) == 0)
-		return 0;
-	return 1;
-}
-
-/**
  * gdata_gd_who_get_relation_type:
  * @self: a #GDataGDWho
  *
diff --git a/gdata/gd/gdata-gd-who.h b/gdata/gd/gdata-gd-who.h
index 1d1322c..213762d 100644
--- a/gdata/gd/gdata-gd-who.h
+++ b/gdata/gd/gdata-gd-who.h
@@ -102,7 +102,6 @@ GType gdata_gd_who_get_type (void) G_GNUC_CONST;
 
 GDataGDWho *gdata_gd_who_new (const gchar *relation_type, const gchar *value_string,
                               const gchar *email_address) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-gint gdata_gd_who_compare (const GDataGDWho *a, const GDataGDWho *b) G_GNUC_PURE;
 
 const gchar *gdata_gd_who_get_relation_type (GDataGDWho *self) G_GNUC_PURE;
 void gdata_gd_who_set_relation_type (GDataGDWho *self, const gchar *relation_type);
diff --git a/gdata/gdata-comparable.c b/gdata/gdata-comparable.c
new file mode 100644
index 0000000..2047e13
--- /dev/null
+++ b/gdata/gdata-comparable.c
@@ -0,0 +1,95 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2010 <philip tecnocode co uk>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdata-comparable
+ * @short_description: GData comparable interface
+ * @stability: Unstable
+ * @include: gdata/gdata-comparable.h
+ *
+ * #GDataComparable is an interface which can be implemented by any object which needs to be compared to another object of the same type or of a
+ * derived type.
+ *
+ * When implementing the interface, classes must implement the <function>compare_with</function> function, and the implementation must be
+ * <ulink type="http" url="http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#index-g_t_0040code_007bpure_007d-function-attribute-2413";>pure
+ * </ulink>.
+ *
+ * Since: 0.7.0
+ **/
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gdata-comparable.h"
+
+GType
+gdata_comparable_get_type (void)
+{
+	static GType comparable_type = 0;
+
+	if (!comparable_type) {
+		comparable_type = g_type_register_static_simple (G_TYPE_INTERFACE, "GDataComparable",
+		                                                 sizeof (GDataComparableIface),
+		                                                 NULL, 0, NULL, 0);
+	}
+
+	return comparable_type;
+}
+
+/**
+ * gdata_comparable_compare:
+ * @self: a #GDataComparable, or %NULL
+ * @other: another #GDataComparable of the same type, or %NULL
+ *
+ * Compares the two objects, returning <code class="literal">-1</code> if @self is "less than" @other by some metric, <code class="literal">0</code>
+ * if they're equal, or <code class="literal">1</code> if @self is "greater than" @other.
+ *
+ * %NULL values are handled gracefully, with <code class="literal">0</code> returned if both @self and @other are %NULL,
+ * <code class="literal">-1</code> if @self is %NULL and <code class="literal">1</code> if @other is %NULL.
+ *
+ * The @other object must be of the same type as @self, or of a type derived from @self's type.
+ *
+ * Return value: %TRUE on success, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ **/
+gint
+gdata_comparable_compare (GDataComparable *self, GDataComparable *other)
+{
+	GDataComparableIface *iface;
+
+	g_return_val_if_fail (self == NULL || GDATA_IS_COMPARABLE (self), 0);
+	g_return_val_if_fail (other == NULL || GDATA_IS_COMPARABLE (other), 0);
+	g_return_val_if_fail (self == NULL || other == NULL || g_type_is_a (G_OBJECT_TYPE (other), G_OBJECT_TYPE (self)), 0);
+
+	/* Deal with NULL values */
+	if (self == NULL && other != NULL)
+		return -1;
+	else if (self != NULL && other == NULL)
+		return 1;
+
+	if (self == other)
+		return 0;
+
+	/* Use the comparator method for non-NULL values */
+	iface = GDATA_COMPARABLE_GET_IFACE (self);
+	g_assert (iface->compare_with != NULL);
+
+	return iface->compare_with (self, other);
+}
diff --git a/gdata/gdata-comparable.h b/gdata/gdata-comparable.h
new file mode 100644
index 0000000..f5b1f64
--- /dev/null
+++ b/gdata/gdata-comparable.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2010 <philip tecnocode co uk>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GDATA_COMPARABLE_H
+#define GDATA_COMPARABLE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_COMPARABLE		(gdata_comparable_get_type ())
+#define GDATA_COMPARABLE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_COMPARABLE, GDataComparable))
+#define GDATA_COMPARABLE_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_COMPARABLE, GDataComparableIface))
+#define GDATA_IS_COMPARABLE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_COMPARABLE))
+#define GDATA_COMPARABLE_GET_IFACE(o)	(G_TYPE_INSTANCE_GET_INTERFACE ((o), GDATA_TYPE_COMPARABLE, GDataComparableIface))
+
+/**
+ * GDataComparable:
+ *
+ * All the fields in the #GDataComparable structure are private and should never be accessed directly.
+ *
+ * Since: 0.7.0
+ **/
+typedef struct _GDataComparable		GDataComparable; /* dummy typedef */
+
+/**
+ * GDataComparableIface:
+ * @parent: the parent type
+ * @compare_with: compares the object with an @other object of the same type, returning <code class="literal">-1</code> if the object is "less than"
+ * the other object, <code class="literal">0</code> if they're equal, or <code class="literal">1</code> if the object is "greater than" the other. The
+ * function can assume that neither @self or @other will be %NULL, and that both have correct types. The function must be pure.
+ *
+ * The class structure for the #GDataComparable interface.
+ *
+ * Since: 0.7.0
+ **/
+typedef struct {
+	GTypeInterface parent;
+
+	gint (*compare_with) (GDataComparable *self, GDataComparable *other);
+} GDataComparableIface;
+
+GType gdata_comparable_get_type (void) G_GNUC_CONST;
+
+gint gdata_comparable_compare (GDataComparable *self, GDataComparable *other) G_GNUC_PURE;
+
+G_END_DECLS
+
+#endif /* !GDATA_COMPARABLE_H */
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index e70d8ab..a925030 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -38,6 +38,7 @@
 #include "gdata-types.h"
 #include "gdata-service.h"
 #include "gdata-private.h"
+#include "gdata-comparable.h"
 #include "atom/gdata-category.h"
 #include "atom/gdata-link.h"
 #include "atom/gdata-author.h"
@@ -650,7 +651,7 @@ gdata_entry_add_category (GDataEntry *self, GDataCategory *category)
 	g_return_if_fail (GDATA_IS_ENTRY (self));
 	g_return_if_fail (GDATA_IS_CATEGORY (category));
 
-	if (g_list_find_custom (self->priv->categories, category, (GCompareFunc) gdata_category_compare) == NULL)
+	if (g_list_find_custom (self->priv->categories, category, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->categories = g_list_prepend (self->priv->categories, g_object_ref (category));
 }
 
@@ -736,7 +737,7 @@ gdata_entry_add_link (GDataEntry *self, GDataLink *link)
 	g_return_if_fail (GDATA_IS_ENTRY (self));
 	g_return_if_fail (GDATA_IS_LINK (link));
 
-	if (g_list_find_custom (self->priv->links, link, (GCompareFunc) gdata_link_compare) == NULL)
+	if (g_list_find_custom (self->priv->links, link, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->links = g_list_prepend (self->priv->links, g_object_ref (link));
 }
 
@@ -821,7 +822,7 @@ gdata_entry_add_author (GDataEntry *self, GDataAuthor *author)
 	g_return_if_fail (GDATA_IS_ENTRY (self));
 	g_return_if_fail (GDATA_IS_AUTHOR (author));
 
-	if (g_list_find_custom (self->priv->authors, author, (GCompareFunc) gdata_author_compare) == NULL)
+	if (g_list_find_custom (self->priv->authors, author, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->authors = g_list_prepend (self->priv->authors, g_object_ref (author));
 }
 
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 7f0c5ef..1c57d6d 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -32,6 +32,7 @@
 #include <gdata/gdata-parsable.h>
 #include <gdata/gdata-download-stream.h>
 #include <gdata/gdata-upload-stream.h>
+#include <gdata/gdata-comparable.h>
 
 /* Namespaces */
 
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index daf63fa..1535ed6 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -323,7 +323,6 @@ gdata_calendar_feed_get_timezone
 gdata_calendar_feed_get_times_cleaned
 gdata_category_get_type
 gdata_category_new
-gdata_category_compare
 gdata_category_get_term
 gdata_category_set_term
 gdata_category_get_scheme
@@ -332,7 +331,6 @@ gdata_category_get_label
 gdata_category_set_label
 gdata_link_get_type
 gdata_link_new
-gdata_link_compare
 gdata_link_get_uri
 gdata_link_set_uri
 gdata_link_get_relation_type
@@ -347,7 +345,6 @@ gdata_link_get_length
 gdata_link_set_length
 gdata_author_get_type
 gdata_author_new
-gdata_author_compare
 gdata_author_get_name
 gdata_author_set_name
 gdata_author_get_uri
@@ -355,13 +352,11 @@ gdata_author_set_uri
 gdata_author_get_email_address
 gdata_author_set_email_address
 gdata_generator_get_type
-gdata_generator_compare
 gdata_generator_get_name
 gdata_generator_get_uri
 gdata_generator_get_version
 gdata_gd_organization_get_type
 gdata_gd_organization_new
-gdata_gd_organization_compare
 gdata_gd_organization_get_name
 gdata_gd_organization_set_name
 gdata_gd_organization_get_title
@@ -382,7 +377,6 @@ gdata_gd_organization_get_location
 gdata_gd_organization_set_location
 gdata_gd_when_get_type
 gdata_gd_when_new
-gdata_gd_when_compare
 gdata_gd_when_get_start_time
 gdata_gd_when_set_start_time
 gdata_gd_when_get_end_time
@@ -395,7 +389,6 @@ gdata_gd_when_get_reminders
 gdata_gd_when_add_reminder
 gdata_gd_who_get_type
 gdata_gd_who_new
-gdata_gd_who_compare
 gdata_gd_who_get_relation_type
 gdata_gd_who_set_relation_type
 gdata_gd_who_get_value_string
@@ -404,7 +397,6 @@ gdata_gd_who_get_email_address
 gdata_gd_who_set_email_address
 gdata_gd_where_get_type
 gdata_gd_where_new
-gdata_gd_where_compare
 gdata_gd_where_get_relation_type
 gdata_gd_where_set_relation_type
 gdata_gd_where_get_value_string
@@ -413,7 +405,6 @@ gdata_gd_where_get_label
 gdata_gd_where_set_label
 gdata_gd_email_address_get_type
 gdata_gd_email_address_new
-gdata_gd_email_address_compare
 gdata_gd_email_address_get_address
 gdata_gd_email_address_set_address
 gdata_gd_email_address_get_relation_type
@@ -426,7 +417,6 @@ gdata_gd_email_address_get_display_name
 gdata_gd_email_address_set_display_name
 gdata_gd_im_address_get_type
 gdata_gd_im_address_new
-gdata_gd_im_address_compare
 gdata_gd_im_address_get_address
 gdata_gd_im_address_set_address
 gdata_gd_im_address_get_protocol
@@ -439,7 +429,6 @@ gdata_gd_im_address_is_primary
 gdata_gd_im_address_set_is_primary
 gdata_gd_postal_address_get_type
 gdata_gd_postal_address_new
-gdata_gd_postal_address_compare
 gdata_gd_postal_address_get_address
 gdata_gd_postal_address_set_address
 gdata_gd_postal_address_get_relation_type
@@ -475,7 +464,6 @@ gdata_gd_postal_address_get_country_code
 gdata_gd_postal_address_set_country
 gdata_gd_phone_number_get_type
 gdata_gd_phone_number_new
-gdata_gd_phone_number_compare
 gdata_gd_phone_number_get_number
 gdata_gd_phone_number_set_number
 gdata_gd_phone_number_get_uri
@@ -488,7 +476,6 @@ gdata_gd_phone_number_is_primary
 gdata_gd_phone_number_set_is_primary
 gdata_gd_reminder_get_type
 gdata_gd_reminder_new
-gdata_gd_reminder_compare
 gdata_gd_reminder_get_method
 gdata_gd_reminder_set_method
 gdata_gd_reminder_get_absolute_time
@@ -702,7 +689,6 @@ gdata_upload_stream_get_slug
 gdata_upload_stream_get_content_type
 gdata_gd_name_get_type
 gdata_gd_name_new
-gdata_gd_name_compare
 gdata_gd_name_get_given_name
 gdata_gd_name_set_given_name
 gdata_gd_name_get_additional_name
@@ -742,7 +728,6 @@ gdata_contacts_contact_get_relations
 gdata_contacts_contact_remove_all_relations
 gdata_gcontact_website_get_type
 gdata_gcontact_website_new
-gdata_gcontact_website_compare
 gdata_gcontact_website_get_uri
 gdata_gcontact_website_set_uri
 gdata_gcontact_website_get_relation_type
@@ -768,7 +753,6 @@ gdata_contacts_contact_get_events
 gdata_contacts_contact_remove_all_events
 gdata_gcontact_calendar_get_type
 gdata_gcontact_calendar_new
-gdata_gcontact_calendar_compare
 gdata_gcontact_calendar_get_uri
 gdata_gcontact_calendar_set_uri
 gdata_gcontact_calendar_get_relation_type
@@ -808,7 +792,6 @@ gdata_contacts_contact_get_user_defined_fields
 gdata_contacts_contact_set_user_defined_field
 gdata_gcontact_external_id_get_type
 gdata_gcontact_external_id_new
-gdata_gcontact_external_id_compare
 gdata_gcontact_external_id_get_value
 gdata_gcontact_external_id_set_value
 gdata_gcontact_external_id_get_relation_type
@@ -823,7 +806,6 @@ gdata_contacts_contact_get_hobbies
 gdata_contacts_contact_remove_all_hobbies
 gdata_gcontact_language_get_type
 gdata_gcontact_language_new
-gdata_gcontact_language_compare
 gdata_gcontact_language_get_code
 gdata_gcontact_language_set_code
 gdata_gcontact_language_get_label
@@ -845,3 +827,5 @@ gdata_youtube_category_is_deprecated
 gdata_app_categories_get_type
 gdata_app_categories_get_categories
 gdata_app_categories_is_fixed
+gdata_comparable_get_type
+gdata_comparable_compare
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index 7d7fbbf..4c0053c 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -40,6 +40,7 @@
 #include "gdata-service.h"
 #include "gdata-parser.h"
 #include "gdata-types.h"
+#include "gdata-comparable.h"
 
 static void gdata_calendar_event_dispose (GObject *object);
 static void gdata_calendar_event_finalize (GObject *object);
@@ -977,7 +978,7 @@ gdata_calendar_event_add_person (GDataCalendarEvent *self, GDataGDWho *who)
 	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
 	g_return_if_fail (GDATA_IS_GD_WHO (who));
 
-	if (g_list_find_custom (self->priv->people, who, (GCompareFunc) gdata_gd_who_compare) == NULL)
+	if (g_list_find_custom (self->priv->people, who, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->people = g_list_append (self->priv->people, g_object_ref (who));
 }
 
@@ -1013,7 +1014,7 @@ gdata_calendar_event_add_place (GDataCalendarEvent *self, GDataGDWhere *where)
 	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
 	g_return_if_fail (GDATA_IS_GD_WHERE (where));
 
-	if (g_list_find_custom (self->priv->places, where, (GCompareFunc) gdata_gd_where_compare) == NULL)
+	if (g_list_find_custom (self->priv->places, where, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->places = g_list_append (self->priv->places, g_object_ref (where));
 }
 
@@ -1051,7 +1052,7 @@ gdata_calendar_event_add_time (GDataCalendarEvent *self, GDataGDWhen *when)
 	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
 	g_return_if_fail (GDATA_IS_GD_WHEN (when));
 
-	if (g_list_find_custom (self->priv->times, when, (GCompareFunc) gdata_gd_when_compare) == NULL)
+	if (g_list_find_custom (self->priv->times, when, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->times = g_list_append (self->priv->times, g_object_ref (when));
 }
 
diff --git a/gdata/services/contacts/gdata-contacts-contact.c b/gdata/services/contacts/gdata-contacts-contact.c
index fa0591e..b8e6de5 100644
--- a/gdata/services/contacts/gdata-contacts-contact.c
+++ b/gdata/services/contacts/gdata-contacts-contact.c
@@ -48,6 +48,7 @@
 #include "gdata-parser.h"
 #include "gdata-types.h"
 #include "gdata-private.h"
+#include "gdata-comparable.h"
 
 /* The maximum number of extended properties the server allows us. See
  * http://code.google.com/apis/contacts/docs/2.0/reference.html#ProjectionsAndExtended.
@@ -1622,7 +1623,7 @@ gdata_contacts_contact_add_email_address (GDataContactsContact *self, GDataGDEma
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GD_EMAIL_ADDRESS (email_address));
 
-	if (g_list_find_custom (self->priv->email_addresses, email_address, (GCompareFunc) gdata_gd_email_address_compare) == NULL)
+	if (g_list_find_custom (self->priv->email_addresses, email_address, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->email_addresses = g_list_append (self->priv->email_addresses, g_object_ref (email_address));
 }
 
@@ -1711,7 +1712,7 @@ gdata_contacts_contact_add_im_address (GDataContactsContact *self, GDataGDIMAddr
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GD_IM_ADDRESS (im_address));
 
-	if (g_list_find_custom (self->priv->im_addresses, im_address, (GCompareFunc) gdata_gd_im_address_compare) == NULL)
+	if (g_list_find_custom (self->priv->im_addresses, im_address, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->im_addresses = g_list_append (self->priv->im_addresses, g_object_ref (im_address));
 }
 
@@ -1800,7 +1801,7 @@ gdata_contacts_contact_add_phone_number (GDataContactsContact *self, GDataGDPhon
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GD_PHONE_NUMBER (phone_number));
 
-	if (g_list_find_custom (self->priv->phone_numbers, phone_number, (GCompareFunc) gdata_gd_phone_number_compare) == NULL)
+	if (g_list_find_custom (self->priv->phone_numbers, phone_number, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->phone_numbers = g_list_append (self->priv->phone_numbers, g_object_ref (phone_number));
 }
 
@@ -1889,7 +1890,7 @@ gdata_contacts_contact_add_postal_address (GDataContactsContact *self, GDataGDPo
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GD_POSTAL_ADDRESS (postal_address));
 
-	if (g_list_find_custom (self->priv->postal_addresses, postal_address, (GCompareFunc) gdata_gd_postal_address_compare) == NULL)
+	if (g_list_find_custom (self->priv->postal_addresses, postal_address, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->postal_addresses = g_list_append (self->priv->postal_addresses, g_object_ref (postal_address));
 }
 
@@ -1978,7 +1979,7 @@ gdata_contacts_contact_add_organization (GDataContactsContact *self, GDataGDOrga
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (organization != NULL);
 
-	if (g_list_find_custom (self->priv->organizations, organization, (GCompareFunc) gdata_gd_organization_compare) == NULL)
+	if (g_list_find_custom (self->priv->organizations, organization, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->organizations = g_list_append (self->priv->organizations, g_object_ref (organization));
 }
 
@@ -2183,7 +2184,7 @@ gdata_contacts_contact_add_website (GDataContactsContact *self, GDataGContactWeb
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GCONTACT_WEBSITE (website));
 
-	if (g_list_find_custom (self->priv->websites, website, (GCompareFunc) gdata_gcontact_website_compare) == NULL)
+	if (g_list_find_custom (self->priv->websites, website, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->websites = g_list_append (self->priv->websites, g_object_ref (website));
 }
 
@@ -2329,7 +2330,7 @@ gdata_contacts_contact_add_calendar (GDataContactsContact *self, GDataGContactCa
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GCONTACT_CALENDAR (calendar));
 
-	if (g_list_find_custom (self->priv->calendars, calendar, (GCompareFunc) gdata_gcontact_calendar_compare) == NULL)
+	if (g_list_find_custom (self->priv->calendars, calendar, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->calendars = g_list_append (self->priv->calendars, g_object_ref (calendar));
 }
 
@@ -2414,7 +2415,7 @@ gdata_contacts_contact_add_external_id (GDataContactsContact *self, GDataGContac
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GCONTACT_EXTERNAL_ID (external_id));
 
-	if (g_list_find_custom (self->priv->external_ids, external_id, (GCompareFunc) gdata_gcontact_external_id_compare) == NULL)
+	if (g_list_find_custom (self->priv->external_ids, external_id, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->external_ids = g_list_append (self->priv->external_ids, g_object_ref (external_id));
 }
 
@@ -2534,7 +2535,7 @@ gdata_contacts_contact_add_language (GDataContactsContact *self, GDataGContactLa
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (GDATA_IS_GCONTACT_LANGUAGE (language));
 
-	if (g_list_find_custom (self->priv->languages, language, (GCompareFunc) gdata_gcontact_language_compare) == NULL)
+	if (g_list_find_custom (self->priv->languages, language, (GCompareFunc) gdata_comparable_compare) == NULL)
 		self->priv->languages = g_list_append (self->priv->languages, g_object_ref (language));
 }
 
diff --git a/gdata/tests/general.c b/gdata/tests/general.c
index 4af4bca..e9e09e9 100644
--- a/gdata/tests/general.c
+++ b/gdata/tests/general.c
@@ -833,6 +833,18 @@ test_access_rule_error_handling (void)
 }
 
 static void
+test_comparable (void)
+{
+	GDataComparable *category = GDATA_COMPARABLE (gdata_category_new ("term", "http://scheme";, "label"));
+
+	/* Test the NULL comparisons */
+	g_assert_cmpint (gdata_comparable_compare (category, NULL), ==, 1);
+	g_assert_cmpint (gdata_comparable_compare (NULL, category), ==, -1);
+	g_assert_cmpint (gdata_comparable_compare (NULL, NULL), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (category, category), ==, 0);
+}
+
+static void
 test_color_parsing (void)
 {
 	GDataColor color;
@@ -921,20 +933,14 @@ test_atom_author (void)
 
 	/* Compare it against another identical author */
 	author2 = gdata_author_new ("John Smöth", "http://example.com/";, "john example com");
-	g_assert_cmpint (gdata_author_compare (author, author2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (author), GDATA_COMPARABLE (author2)), ==, 0);
 	g_object_unref (author2);
 
 	/* â?¦and a different author */
 	author2 = gdata_author_new ("Brian Blessed", NULL, NULL);
-	g_assert_cmpint (gdata_author_compare (author, author2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (author), GDATA_COMPARABLE (author2)), !=, 0);
 	g_object_unref (author2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_author_compare (author, NULL), ==, 1);
-	g_assert_cmpint (gdata_author_compare (NULL, author), ==, -1);
-	g_assert_cmpint (gdata_author_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_author_compare (author, author), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (author));
 	g_assert_cmpstr (xml, ==,
@@ -1027,20 +1033,14 @@ test_atom_category (void)
 
 	/* Compare it against another identical category */
 	category2 = gdata_category_new ("jokes", "http://foobar.com#categories";, "Jokes & Trivia");
-	g_assert_cmpint (gdata_category_compare (category, category2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (category), GDATA_COMPARABLE (category2)), ==, 0);
 	g_object_unref (category2);
 
 	/* â?¦and a different category */
 	category2 = gdata_category_new ("sports", "http://foobar.com#categories";, NULL);
-	g_assert_cmpint (gdata_category_compare (category, category2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (category), GDATA_COMPARABLE (category2)), !=, 0);
 	g_object_unref (category2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_category_compare (category, NULL), ==, 1);
-	g_assert_cmpint (gdata_category_compare (NULL, category), ==, -1);
-	g_assert_cmpint (gdata_category_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_category_compare (category, category), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (category));
 	g_assert_cmpstr (xml, ==,
@@ -1129,7 +1129,7 @@ test_atom_generator (void)
 	/* Compare it against another identical generator */
 	generator2 = GDATA_GENERATOR (gdata_parsable_new_from_xml (GDATA_TYPE_GENERATOR,
 		"<generator uri='http://example.com/' version='15'>Bach &amp; Son's Generator</generator>", -1, NULL));
-	g_assert_cmpint (gdata_generator_compare (generator, generator2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (generator), GDATA_COMPARABLE (generator2)), ==, 0);
 	g_object_unref (generator2);
 
 	/* â?¦and a different generator */
@@ -1137,15 +1137,9 @@ test_atom_generator (void)
 		"<generator>Different generator</generator>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_GENERATOR (generator));
-	g_assert_cmpint (gdata_generator_compare (generator, generator2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (generator), GDATA_COMPARABLE (generator2)), !=, 0);
 	g_object_unref (generator2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_generator_compare (generator, NULL), ==, 1);
-	g_assert_cmpint (gdata_generator_compare (NULL, generator), ==, -1);
-	g_assert_cmpint (gdata_generator_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_generator_compare (generator, generator), ==, 0);
-
 	/* Check the properties */
 	g_assert_cmpstr (gdata_generator_get_name (generator), ==, "Bach & Son's Generator");
 	g_assert_cmpstr (gdata_generator_get_uri (generator), ==, "http://example.com/";);
@@ -1219,24 +1213,18 @@ test_atom_link (void)
 
 	/* Compare it against another identical link */
 	link2 = gdata_link_new ("http://example.com/";, "http://test.com#link-type";);
-	g_assert_cmpint (gdata_link_compare (link1, link2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (link1), GDATA_COMPARABLE (link2)), ==, 0);
 	gdata_link_set_content_type (link2, "text/plain");
 	gdata_link_set_language (link2, "de");
 	gdata_link_set_title (link2, "All About Angle Brackets: <, >");
 	gdata_link_set_length (link2, 2000);
-	g_assert_cmpint (gdata_link_compare (link1, link2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (link1), GDATA_COMPARABLE (link2)), ==, 0);
 
 	/* Try with a dissimilar link */
 	gdata_link_set_uri (link2, "http://gnome.org/";);
-	g_assert_cmpint (gdata_link_compare (link1, link2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (link1), GDATA_COMPARABLE (link2)), !=, 0);
 	g_object_unref (link2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_link_compare (link1, NULL), ==, 1);
-	g_assert_cmpint (gdata_link_compare (NULL, link1), ==, -1);
-	g_assert_cmpint (gdata_link_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_link_compare (link1, link1), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (link1));
 	g_assert_cmpstr (xml, ==,
@@ -1404,19 +1392,13 @@ test_gd_email_address (void)
 	/* Compare it against another identical address */
 	email2 = gdata_gd_email_address_new ("fubar gmail com", GDATA_GD_EMAIL_ADDRESS_HOME, "Personal & Private", TRUE);
 	gdata_gd_email_address_set_display_name (email2, "<John Smith>");
-	g_assert_cmpint (gdata_gd_email_address_compare (email, email2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (email), GDATA_COMPARABLE (email2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_email_address_set_address (email2, "test example com");
-	g_assert_cmpint (gdata_gd_email_address_compare (email, email2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (email), GDATA_COMPARABLE (email2)), !=, 0);
 	g_object_unref (email2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_email_address_compare (email, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_email_address_compare (NULL, email), ==, -1);
-	g_assert_cmpint (gdata_gd_email_address_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_email_address_compare (email, email), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (email));
 	g_assert_cmpstr (xml, ==,
@@ -1474,19 +1456,13 @@ test_gd_im_address (void)
 
 	/* Compare it against another identical address */
 	im2 = gdata_gd_im_address_new ("foo bar msn com", GDATA_GD_IM_PROTOCOL_LIVE_MESSENGER, GDATA_GD_IM_ADDRESS_HOME, NULL, TRUE);
-	g_assert_cmpint (gdata_gd_im_address_compare (im, im2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (im), GDATA_COMPARABLE (im2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_im_address_set_protocol (im2, GDATA_GD_IM_PROTOCOL_GOOGLE_TALK);
-	g_assert_cmpint (gdata_gd_im_address_compare (im, im2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (im), GDATA_COMPARABLE (im2)), !=, 0);
 	g_object_unref (im2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_im_address_compare (im, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_im_address_compare (NULL, im), ==, -1);
-	g_assert_cmpint (gdata_gd_im_address_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_im_address_compare (im, im), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (im));
 	g_assert_cmpstr (xml, ==,
@@ -1554,19 +1530,13 @@ test_gd_name (void)
 	gdata_gd_name_set_additional_name (name2, "Charles");
 	gdata_gd_name_set_prefix (name2, "Mr");
 	gdata_gd_name_set_suffix (name2, "ABC");
-	g_assert_cmpint (gdata_gd_name_compare (name, name2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (name), GDATA_COMPARABLE (name2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_name_set_prefix (name2, "Mrs");
-	g_assert_cmpint (gdata_gd_name_compare (name, name2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (name), GDATA_COMPARABLE (name2)), !=, 0);
 	g_object_unref (name2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_name_compare (name, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_name_compare (NULL, name), ==, -1);
-	g_assert_cmpint (gdata_gd_name_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_name_compare (name, name), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (name));
 	g_assert_cmpstr (xml, ==,
@@ -1646,19 +1616,13 @@ test_gd_organization (void)
 	org2 = gdata_gd_organization_new ("Google, Inc.", "<Angle Bracketeer>", GDATA_GD_ORGANIZATION_WORK, "Work & Occupation", TRUE);
 	gdata_gd_organization_set_department (org2, "Finance");
 	gdata_gd_organization_set_location (org2, location);
-	g_assert_cmpint (gdata_gd_organization_compare (org, org2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (org), GDATA_COMPARABLE (org2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_organization_set_title (org2, "Demoted!");
-	g_assert_cmpint (gdata_gd_organization_compare (org, org2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (org), GDATA_COMPARABLE (org2)), !=, 0);
 	g_object_unref (org2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_organization_compare (org, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_organization_compare (NULL, org), ==, -1);
-	g_assert_cmpint (gdata_gd_organization_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_organization_compare (org, org), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (org));
 	g_assert_cmpstr (xml, ==,
@@ -1726,19 +1690,13 @@ test_gd_phone_number (void)
 	/* Compare it against another identical number */
 	phone2 = gdata_gd_phone_number_new ("+1 206 555 1212", GDATA_GD_PHONE_NUMBER_MOBILE, "Personal & business calls only",
 					    "tel:+12065551212", FALSE);
-	g_assert_cmpint (gdata_gd_phone_number_compare (phone, phone2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (phone), GDATA_COMPARABLE (phone2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_phone_number_set_number (phone2, "+1 206 555 1212 666");
-	g_assert_cmpint (gdata_gd_phone_number_compare (phone, phone2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (phone), GDATA_COMPARABLE (phone2)), !=, 0);
 	g_object_unref (phone2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_phone_number_compare (phone, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_phone_number_compare (NULL, phone), ==, -1);
-	g_assert_cmpint (gdata_gd_phone_number_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_phone_number_compare (phone, phone), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (phone));
 	g_assert_cmpstr (xml, ==,
@@ -1808,19 +1766,13 @@ test_gd_postal_address (void)
 	gdata_gd_postal_address_set_street (postal2, "500 West 45th Street");
 	gdata_gd_postal_address_set_city (postal2, "New York");
 	gdata_gd_postal_address_set_postcode (postal2, "NY 10036");
-	g_assert_cmpint (gdata_gd_postal_address_compare (postal, postal2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (postal), GDATA_COMPARABLE (postal2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_postal_address_set_city (postal2, "Atlas Mountains");
-	g_assert_cmpint (gdata_gd_postal_address_compare (postal, postal2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (postal), GDATA_COMPARABLE (postal2)), !=, 0);
 	g_object_unref (postal2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_postal_address_compare (postal, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_postal_address_compare (NULL, postal), ==, -1);
-	g_assert_cmpint (gdata_gd_postal_address_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_postal_address_compare (postal, postal), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (postal));
 	g_assert_cmpstr (xml, ==,
@@ -1903,7 +1855,7 @@ test_gd_reminder (void)
 
 	/* Compare to another reminder */
 	reminder2 = gdata_gd_reminder_new (NULL, NULL, 15 * 60);
-	g_assert_cmpint (gdata_gd_reminder_compare (reminder, reminder2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (reminder), GDATA_COMPARABLE (reminder2)), ==, 0);
 	g_object_unref (reminder2);
 	g_object_unref (reminder);
 
@@ -1914,12 +1866,6 @@ test_gd_reminder (void)
 	g_assert (GDATA_IS_GD_REMINDER (reminder));
 	g_clear_error (&error);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_reminder_compare (reminder, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_reminder_compare (NULL, reminder), ==, -1);
-	g_assert_cmpint (gdata_gd_reminder_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_reminder_compare (reminder, reminder), ==, 0);
-
 	/* Check the properties */
 	g_assert (gdata_gd_reminder_get_method (reminder) == NULL);
 	g_assert (gdata_gd_reminder_is_absolute_time (reminder) == FALSE);
@@ -1942,7 +1888,7 @@ test_gd_reminder (void)
 
 	/* Compare to another reminder */
 	reminder2 = gdata_gd_reminder_new (GDATA_GD_REMINDER_ALERT, &time_val, -1);
-	g_assert_cmpint (gdata_gd_reminder_compare (reminder, reminder2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (reminder), GDATA_COMPARABLE (reminder2)), ==, 0);
 	g_object_unref (reminder2);
 
 	/* Check the outputted XML */
@@ -1985,20 +1931,14 @@ test_gd_when (void)
 
 	/* Compare it against another identical time */
 	when2 = gdata_gd_when_new (&time_val, &time_val2, FALSE);
-	g_assert_cmpint (gdata_gd_when_compare (when, when2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (when), GDATA_COMPARABLE (when2)), ==, 0);
 
 	/* â?¦and a different one */
 	time_val2.tv_usec = 100;
 	gdata_gd_when_set_end_time (when2, &time_val2);
-	g_assert_cmpint (gdata_gd_when_compare (when, when2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (when), GDATA_COMPARABLE (when2)), !=, 0);
 	g_object_unref (when2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_when_compare (when, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_when_compare (NULL, when), ==, -1);
-	g_assert_cmpint (gdata_gd_when_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_when_compare (when, when), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (when));
 	g_assert_cmpstr (xml, ==,
@@ -2075,19 +2015,13 @@ test_gd_where (void)
 
 	/* Compare it against another identical place */
 	where2 = gdata_gd_where_new (GDATA_GD_WHERE_EVENT_ALTERNATE, "Metropolis", "New York Location <videoconference>");
-	g_assert_cmpint (gdata_gd_where_compare (where, where2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (where), GDATA_COMPARABLE (where2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_where_set_label (where2, "Atlas Mountains");
-	g_assert_cmpint (gdata_gd_where_compare (where, where2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (where), GDATA_COMPARABLE (where2)), !=, 0);
 	g_object_unref (where2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_where_compare (where, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_where_compare (NULL, where), ==, -1);
-	g_assert_cmpint (gdata_gd_where_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_where_compare (where, where), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (where));
 	g_assert_cmpstr (xml, ==,
@@ -2141,19 +2075,13 @@ test_gd_who (void)
 
 	/* Compare it against another identical person */
 	who2 = gdata_gd_who_new ("http://schemas.google.com/g/2005#message.to";, "Elizabeth", "liz example com");
-	g_assert_cmpint (gdata_gd_who_compare (who, who2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (who), GDATA_COMPARABLE (who2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gd_who_set_email_address (who2, "john example com");
-	g_assert_cmpint (gdata_gd_who_compare (who, who2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (who), GDATA_COMPARABLE (who2)), !=, 0);
 	g_object_unref (who2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gd_who_compare (who, NULL), ==, 1);
-	g_assert_cmpint (gdata_gd_who_compare (NULL, who), ==, -1);
-	g_assert_cmpint (gdata_gd_who_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gd_who_compare (who, who), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (who));
 	g_assert_cmpstr (xml, ==,
@@ -2511,19 +2439,13 @@ test_gcontact_calendar (void)
 
 	/* Compare it against another identical calendar */
 	calendar2 = gdata_gcontact_calendar_new ("http://calendar.com/";, GDATA_GCONTACT_CALENDAR_WORK, NULL, TRUE);
-	g_assert_cmpint (gdata_gcontact_calendar_compare (calendar, calendar2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (calendar), GDATA_COMPARABLE (calendar2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gcontact_calendar_set_uri (calendar2, "http://calendar.somewhereelse.com/";);
-	g_assert_cmpint (gdata_gcontact_calendar_compare (calendar, calendar2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (calendar), GDATA_COMPARABLE (calendar2)), !=, 0);
 	g_object_unref (calendar2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gcontact_calendar_compare (calendar, NULL), ==, 1);
-	g_assert_cmpint (gdata_gcontact_calendar_compare (NULL, calendar), ==, -1);
-	g_assert_cmpint (gdata_gcontact_calendar_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gcontact_calendar_compare (calendar, calendar), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (calendar));
 	g_assert_cmpstr (xml, ==,
@@ -2701,19 +2623,13 @@ test_gcontact_external_id (void)
 
 	/* Compare it against another identical external ID */
 	id2 = gdata_gcontact_external_id_new ("5", GDATA_GCONTACT_EXTERNAL_ID_ACCOUNT, NULL);
-	g_assert_cmpint (gdata_gcontact_external_id_compare (id, id2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (id), GDATA_COMPARABLE (id2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gcontact_external_id_set_value (id2, "http://identifying.uri";);
-	g_assert_cmpint (gdata_gcontact_external_id_compare (id, id2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (id), GDATA_COMPARABLE (id2)), !=, 0);
 	g_object_unref (id2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gcontact_external_id_compare (id, NULL), ==, 1);
-	g_assert_cmpint (gdata_gcontact_external_id_compare (NULL, id), ==, -1);
-	g_assert_cmpint (gdata_gcontact_external_id_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gcontact_external_id_compare (id, id), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (id));
 	g_assert_cmpstr (xml, ==,
@@ -2859,19 +2775,13 @@ test_gcontact_language (void)
 
 	/* Compare it against another identical language */
 	language2 = gdata_gcontact_language_new ("en-GB", NULL);
-	g_assert_cmpint (gdata_gcontact_language_compare (language, language2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (language), GDATA_COMPARABLE (language2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gcontact_language_set_code (language2, "sv");
-	g_assert_cmpint (gdata_gcontact_language_compare (language, language2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (language), GDATA_COMPARABLE (language2)), !=, 0);
 	g_object_unref (language2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gcontact_language_compare (language, NULL), ==, 1);
-	g_assert_cmpint (gdata_gcontact_language_compare (NULL, language), ==, -1);
-	g_assert_cmpint (gdata_gcontact_language_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gcontact_language_compare (language, language), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (language));
 	g_assert_cmpstr (xml, ==,
@@ -3024,19 +2934,13 @@ test_gcontact_website (void)
 
 	/* Compare it against another identical website */
 	website2 = gdata_gcontact_website_new ("http://example.com/";, GDATA_GCONTACT_WEBSITE_WORK, "<Markup> blog", TRUE);
-	g_assert_cmpint (gdata_gcontact_website_compare (website, website2), ==, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (website), GDATA_COMPARABLE (website2)), ==, 0);
 
 	/* â?¦and a different one */
 	gdata_gcontact_website_set_uri (website2, "http://somewhereelse.com/";);
-	g_assert_cmpint (gdata_gcontact_website_compare (website, website2), !=, 0);
+	g_assert_cmpint (gdata_comparable_compare (GDATA_COMPARABLE (website), GDATA_COMPARABLE (website2)), !=, 0);
 	g_object_unref (website2);
 
-	/* More comparisons */
-	g_assert_cmpint (gdata_gcontact_website_compare (website, NULL), ==, 1);
-	g_assert_cmpint (gdata_gcontact_website_compare (NULL, website), ==, -1);
-	g_assert_cmpint (gdata_gcontact_website_compare (NULL, NULL), ==, 0);
-	g_assert_cmpint (gdata_gcontact_website_compare (website, website), ==, 0);
-
 	/* Check the outputted XML is the same */
 	xml = gdata_parsable_get_xml (GDATA_PARSABLE (website));
 	g_assert_cmpstr (xml, ==,
@@ -3114,6 +3018,8 @@ main (int argc, char *argv[])
 	g_test_add_func ("/access-rule/get_xml", test_access_rule_get_xml);
 	g_test_add_func ("/access-rule/error_handling", test_access_rule_error_handling);
 
+	g_test_add_func ("/comparable", test_comparable);
+
 	g_test_add_func ("/color/parsing", test_color_parsing);
 	g_test_add_func ("/color/output", test_color_output);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]