diff mbox series

[1/2] object: recommend a few type check macros

Message ID 20180921111332.12973-2-marcandre.lureau@redhat.com
State New
Headers show
Series RFC: object: recommend a few type check macros | expand

Commit Message

Marc-André Lureau Sept. 21, 2018, 11:13 a.m. UTC
I sometime regret that we have to resort to long
object{_class}_dynamic_cast() calls instead of having a shorter and
more readable macros available, similar to the one recommended by
GObject (https://developer.gnome.org/gobject/stable/gtype-conventions.html).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qom/object.h | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

Comments

Eduardo Habkost Sept. 25, 2018, 7:49 p.m. UTC | #1
On Fri, Sep 21, 2018 at 03:13:31PM +0400, Marc-André Lureau wrote:
> I sometime regret that we have to resort to long
> object{_class}_dynamic_cast() calls instead of having a shorter and
> more readable macros available, similar to the one recommended by
> GObject (https://developer.gnome.org/gobject/stable/gtype-conventions.html).
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Nice addition.

Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>

I wonder if we could provide a tool to help us generate and/or
validate all this boilerplate code for new and/or existing types.


> ---
>  include/qom/object.h | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/include/qom/object.h b/include/qom/object.h
> index f0b0bf39cc..c16e0bc91e 100644
> --- a/include/qom/object.h
> +++ b/include/qom/object.h
> @@ -101,24 +101,31 @@ typedef struct InterfaceInfo InterfaceInfo;
>   *   </programlisting>
>   * </example>
>   *
> - * Every type has an #ObjectClass associated with it.  #ObjectClass derivatives
> - * are instantiated dynamically but there is only ever one instance for any
> - * given type.  The #ObjectClass typically holds a table of function pointers
> - * for the virtual methods implemented by this type.
> + * Every type has an #ObjectClass associated with it.  #ObjectClass
> + * derivatives are instantiated dynamically but there is only ever one
> + * instance for any given type.  The #ObjectClass typically holds a
> + * table of function pointers for the virtual methods implemented by
> + * this type. You can cast an #ObjectClass to a subclass (or
> + * base-class) type using object_class_dynamic_cast().
>   *
> - * Using object_new(), a new #Object derivative will be instantiated.  You can
> - * cast an #Object to a subclass (or base-class) type using
> - * object_dynamic_cast().  You typically want to define macro wrappers around
> - * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
> - * specific type:
> + * Using object_new(), a new #Object derivative will be instantiated.
> + * You can cast an #Object to a subclass (or base-class) type using
> + * object_dynamic_cast().
> + *
> + * You typically want to define macro wrappers to make it easier to
> + * handle casting:
>   *
>   * <example>
>   *   <title>Typecasting macros</title>
>   *   <programlisting>
>   *    #define MY_DEVICE_GET_CLASS(obj) \
>   *       OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
> + *    #define IS_MY_DEVICE_CLASS(klass) \
> + *       object_class_dynamic_cast(OBJECT_CLASS(klass), TYPE_MY_DEVICE)
>   *    #define MY_DEVICE_CLASS(klass) \
>   *       OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
> + *    #define IS_MY_DEVICE(obj) \
> + *       object_dynamic_cast(OBJECT(obj), TYPE_MY_DEVICE)
>   *    #define MY_DEVICE(obj) \
>   *       OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
>   *   </programlisting>
> -- 
> 2.19.0
>
Peter Maydell Sept. 27, 2018, 12:42 p.m. UTC | #2
On 21 September 2018 at 12:13, Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
> I sometime regret that we have to resort to long
> object{_class}_dynamic_cast() calls instead of having a shorter and
> more readable macros available, similar to the one recommended by
> GObject (https://developer.gnome.org/gobject/stable/gtype-conventions.html).
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/qom/object.h | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/include/qom/object.h b/include/qom/object.h
> index f0b0bf39cc..c16e0bc91e 100644
> --- a/include/qom/object.h
> +++ b/include/qom/object.h
> @@ -101,24 +101,31 @@ typedef struct InterfaceInfo InterfaceInfo;
>   *   </programlisting>
>   * </example>
>   *
> - * Every type has an #ObjectClass associated with it.  #ObjectClass derivatives
> - * are instantiated dynamically but there is only ever one instance for any
> - * given type.  The #ObjectClass typically holds a table of function pointers
> - * for the virtual methods implemented by this type.
> + * Every type has an #ObjectClass associated with it.  #ObjectClass
> + * derivatives are instantiated dynamically but there is only ever one
> + * instance for any given type.  The #ObjectClass typically holds a
> + * table of function pointers for the virtual methods implemented by
> + * this type. You can cast an #ObjectClass to a subclass (or
> + * base-class) type using object_class_dynamic_cast().
>   *
> - * Using object_new(), a new #Object derivative will be instantiated.  You can
> - * cast an #Object to a subclass (or base-class) type using
> - * object_dynamic_cast().  You typically want to define macro wrappers around
> - * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
> - * specific type:
> + * Using object_new(), a new #Object derivative will be instantiated.
> + * You can cast an #Object to a subclass (or base-class) type using
> + * object_dynamic_cast().
> + *
> + * You typically want to define macro wrappers to make it easier to
> + * handle casting:
>   *
>   * <example>
>   *   <title>Typecasting macros</title>
>   *   <programlisting>
>   *    #define MY_DEVICE_GET_CLASS(obj) \
>   *       OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
> + *    #define IS_MY_DEVICE_CLASS(klass) \
> + *       object_class_dynamic_cast(OBJECT_CLASS(klass), TYPE_MY_DEVICE)
>   *    #define MY_DEVICE_CLASS(klass) \
>   *       OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
> + *    #define IS_MY_DEVICE(obj) \
> + *       object_dynamic_cast(OBJECT(obj), TYPE_MY_DEVICE)
>   *    #define MY_DEVICE(obj) \
>   *       OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
>   *   </programlisting>

I think in general this is a good idea, but I have a couple of
questions:

(1) is this new macro going to become one of the "standard set"
that every QOM object type should provide, like FOO_CLASS
and FOO_GET_CLASS, as noted in
https://wiki.qemu.org/Documentation/QOMConventions
or is it an "on-demand, added to classes where somebody cares" ?

(2) Naming. IS_FOO() implies a boolean return, but
object_dynamic_cast() is "return NULL, or a suitably cast
pointer to the object". (An awful lot of our actual uses
in tree really only seem to want the bool, but I think the
idea was to avoid having the overhead of doing the cast
operation twice.)

thanks
-- PMM
Marc-André Lureau Sept. 27, 2018, 12:52 p.m. UTC | #3
Hi

On Thu, Sep 27, 2018 at 4:42 PM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On 21 September 2018 at 12:13, Marc-André Lureau
> <marcandre.lureau@redhat.com> wrote:
> > I sometime regret that we have to resort to long
> > object{_class}_dynamic_cast() calls instead of having a shorter and
> > more readable macros available, similar to the one recommended by
> > GObject (https://developer.gnome.org/gobject/stable/gtype-conventions.html).
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  include/qom/object.h | 25 ++++++++++++++++---------
> >  1 file changed, 16 insertions(+), 9 deletions(-)
> >
> > diff --git a/include/qom/object.h b/include/qom/object.h
> > index f0b0bf39cc..c16e0bc91e 100644
> > --- a/include/qom/object.h
> > +++ b/include/qom/object.h
> > @@ -101,24 +101,31 @@ typedef struct InterfaceInfo InterfaceInfo;
> >   *   </programlisting>
> >   * </example>
> >   *
> > - * Every type has an #ObjectClass associated with it.  #ObjectClass derivatives
> > - * are instantiated dynamically but there is only ever one instance for any
> > - * given type.  The #ObjectClass typically holds a table of function pointers
> > - * for the virtual methods implemented by this type.
> > + * Every type has an #ObjectClass associated with it.  #ObjectClass
> > + * derivatives are instantiated dynamically but there is only ever one
> > + * instance for any given type.  The #ObjectClass typically holds a
> > + * table of function pointers for the virtual methods implemented by
> > + * this type. You can cast an #ObjectClass to a subclass (or
> > + * base-class) type using object_class_dynamic_cast().
> >   *
> > - * Using object_new(), a new #Object derivative will be instantiated.  You can
> > - * cast an #Object to a subclass (or base-class) type using
> > - * object_dynamic_cast().  You typically want to define macro wrappers around
> > - * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
> > - * specific type:
> > + * Using object_new(), a new #Object derivative will be instantiated.
> > + * You can cast an #Object to a subclass (or base-class) type using
> > + * object_dynamic_cast().
> > + *
> > + * You typically want to define macro wrappers to make it easier to
> > + * handle casting:
> >   *
> >   * <example>
> >   *   <title>Typecasting macros</title>
> >   *   <programlisting>
> >   *    #define MY_DEVICE_GET_CLASS(obj) \
> >   *       OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
> > + *    #define IS_MY_DEVICE_CLASS(klass) \
> > + *       object_class_dynamic_cast(OBJECT_CLASS(klass), TYPE_MY_DEVICE)
> >   *    #define MY_DEVICE_CLASS(klass) \
> >   *       OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
> > + *    #define IS_MY_DEVICE(obj) \
> > + *       object_dynamic_cast(OBJECT(obj), TYPE_MY_DEVICE)
> >   *    #define MY_DEVICE(obj) \
> >   *       OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
> >   *   </programlisting>
>
> I think in general this is a good idea, but I have a couple of
> questions:
>
> (1) is this new macro going to become one of the "standard set"
> that every QOM object type should provide, like FOO_CLASS
> and FOO_GET_CLASS, as noted in
> https://wiki.qemu.org/Documentation/QOMConventions
> or is it an "on-demand, added to classes where somebody cares" ?

My initial approach was "on-demand", since it wasn't used widely. Now,
if we do whole-tree conversion (which I am slowly doing ;), then we
may want to have stricter rules.

>
> (2) Naming. IS_FOO() implies a boolean return, but
> object_dynamic_cast() is "return NULL, or a suitably cast
> pointer to the object". (An awful lot of our actual uses
> in tree really only seem to want the bool, but I think the
> idea was to avoid having the overhead of doing the cast
> operation twice.)

yes, there are these two cases.

In my pending conversion tree, I keep the object_dynamic_cast() to
avoid the double cast operation where it make sense. Otherwise, I use
the IS_FOO().

In general the double cast shouldn't be a performance concern anyway
(or we can use static casting, like what is done in CPU() of
qom/cpu.h)

Alternatively, OBJECT_CLASS_CHECK() could be changed to run
object_class_dynamic_cast_assert() only when --enable-qom-cast-debug,
and do static cast in regular builds.

>
> thanks
> -- PMM
diff mbox series

Patch

diff --git a/include/qom/object.h b/include/qom/object.h
index f0b0bf39cc..c16e0bc91e 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -101,24 +101,31 @@  typedef struct InterfaceInfo InterfaceInfo;
  *   </programlisting>
  * </example>
  *
- * Every type has an #ObjectClass associated with it.  #ObjectClass derivatives
- * are instantiated dynamically but there is only ever one instance for any
- * given type.  The #ObjectClass typically holds a table of function pointers
- * for the virtual methods implemented by this type.
+ * Every type has an #ObjectClass associated with it.  #ObjectClass
+ * derivatives are instantiated dynamically but there is only ever one
+ * instance for any given type.  The #ObjectClass typically holds a
+ * table of function pointers for the virtual methods implemented by
+ * this type. You can cast an #ObjectClass to a subclass (or
+ * base-class) type using object_class_dynamic_cast().
  *
- * Using object_new(), a new #Object derivative will be instantiated.  You can
- * cast an #Object to a subclass (or base-class) type using
- * object_dynamic_cast().  You typically want to define macro wrappers around
- * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
- * specific type:
+ * Using object_new(), a new #Object derivative will be instantiated.
+ * You can cast an #Object to a subclass (or base-class) type using
+ * object_dynamic_cast().
+ *
+ * You typically want to define macro wrappers to make it easier to
+ * handle casting:
  *
  * <example>
  *   <title>Typecasting macros</title>
  *   <programlisting>
  *    #define MY_DEVICE_GET_CLASS(obj) \
  *       OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
+ *    #define IS_MY_DEVICE_CLASS(klass) \
+ *       object_class_dynamic_cast(OBJECT_CLASS(klass), TYPE_MY_DEVICE)
  *    #define MY_DEVICE_CLASS(klass) \
  *       OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
+ *    #define IS_MY_DEVICE(obj) \
+ *       object_dynamic_cast(OBJECT(obj), TYPE_MY_DEVICE)
  *    #define MY_DEVICE(obj) \
  *       OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
  *   </programlisting>