Patchwork [for-1.4] qom: Extend documentation on QOM method concepts

login
register
mail settings
Submitter Andreas Färber
Date Jan. 17, 2013, 7:31 a.m.
Message ID <1358407910-6031-1-git-send-email-afaerber@suse.de>
Download mbox | patch
Permalink /patch/213150/
State New
Headers show

Comments

Andreas Färber - Jan. 17, 2013, 7:31 a.m.
Add a documentation section "Methods" and discuss among others how to
handle overriding virtual methods.

Clarify DeviceClass::realize documentation and refer to the above.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 hw/qdev-core.h       |   14 +++++--
 include/qom/object.h |  104 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 Dateien geändert, 111 Zeilen hinzugefügt(+), 7 Zeilen entfernt(-)
Eduardo Habkost - Jan. 17, 2013, 4:48 p.m.
On Thu, Jan 17, 2013 at 08:31:50AM +0100, Andreas Färber wrote:
> Add a documentation section "Methods" and discuss among others how to
> handle overriding virtual methods.
> 
> Clarify DeviceClass::realize documentation and refer to the above.
> 
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
>  hw/qdev-core.h       |   14 +++++--
>  include/qom/object.h |  104 ++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 Dateien geändert, 111 Zeilen hinzugefügt(+), 7 Zeilen entfernt(-)
> 
> diff --git a/hw/qdev-core.h b/hw/qdev-core.h
> index 3d75ae2..731aadd 100644
> --- a/hw/qdev-core.h
> +++ b/hw/qdev-core.h
> @@ -60,14 +60,20 @@ struct VMStateDescription;
>   * The @init callback is considered private to a particular bus implementation
>   * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
>   * "init" callback on their parent class instead.
> + *
>   * Any type may override the @realize and/or @unrealize callbacks but needs
> - * to call (and thus save) the parent type's implementation if so desired.
> - * Usually this means storing the previous value of, e.g., @realized inside
> - * the type's class structure and overwriting it with a function that first
> - * invokes the stored callback, then performs any additional steps.
> + * to call the parent type's implementation if keeping their functionality
> + * is desired. Refer to QOM documentation for further discussion and examples.
> + *
> + * <note>
> + *   <para>
>   * If a type derived directly from TYPE_DEVICE implements @realize, it does
>   * not need to implement @init and therefore does not need to store and call
>   * #DeviceClass' default @realize callback.
> + * For other types consult the documentation and implementation of the
> + * respective parent types.
> + *   </para>
> + * </note>

The above looks clearer to me, thanks!

But I still have a question about the preferred method to make
subclasses call the parent implementation, below:


>   */
>  typedef struct DeviceClass {
>      /*< private >*/
> diff --git a/include/qom/object.h b/include/qom/object.h
> index 1ef2f0e..8e16ea8 100644
> --- a/include/qom/object.h
> +++ b/include/qom/object.h
> @@ -147,9 +147,9 @@ typedef struct InterfaceInfo InterfaceInfo;
>   *   </programlisting>
>   * </example>
>   *
> - * Introducing new virtual functions requires a class to define its own
> - * struct and to add a .class_size member to the TypeInfo.  Each function
> - * will also have a wrapper to call it easily:
> + * Introducing new virtual methods requires a class to define its own
> + * struct and to add a .class_size member to the #TypeInfo.  Each method
> + * will also have a wrapper function to call it easily:
>   *
>   * <example>
>   *   <title>Defining an abstract class</title>
> @@ -186,6 +186,104 @@ typedef struct InterfaceInfo InterfaceInfo;
>   * similar to normal types except for the fact that are only defined by
>   * their classes and never carry any state.  You can dynamically cast an object
>   * to one of its #Interface types and vice versa.
> + *
> + * # Methods #
> + *
> + * A <emphasis>method</emphasis> is a function within the namespace scope of
> + * a class. It usually operates on the object instance by passing it as a
> + * strongly-typed first argument.
> + * If it does not operate on an object instance, it is dubbed
> + * <emphasis>class method</emphasis>.
> + *
> + * Methods cannot be overloaded. That is, the #ObjectClass and method name
> + * uniquely identity the function to be called; the signature does not vary
> + * except for trailing varargs.
> + *
> + * Methods are always <emphasis>virtual</emphasis>. Overriding a method in
> + * #TypeInfo.class_init of a subclass leads to any user of the class obtained
> + * via OBJECT_GET_CLASS() accessing the overridden function.
> + * The original function is not automatically invoked. It is the responsability
> + * of the overriding class to determine whether and when to invoke the method
> + * being overridden.
> + *
> + * To invoke the method being overridden, the preferred solution is to store
> + * the original value in the overriding class before overriding the method.
> + * This corresponds to |[ {super,base}.method(...) ]| in Java and C#
> + * respectively; this frees the overriding class from hardcoding its parent
> + * class, which someone might choose to change at some point.
> + *
> + * <example>
> + *   <title>Overriding a virtual method</title>
> + *   <programlisting>
> + * typedef struct MyState MyState;
> + *
> + * typedef void (*MyDoSomething)(MyState *obj);
> + *
> + * typedef struct MyClass {
> + *     ObjectClass parent_class;
> + *
> + *     MyDoSomething do_something;
> + * } MyClass;
> + *
> + * static void my_do_something(MyState *obj)
> + * {
> + *     // do something
> + * }
> + *
> + * static void my_class_init(ObjectClass *oc, void *data)
> + * {
> + *     MyClass *mc = MY_CLASS(oc);
> + *
> + *     mc->do_something = my_do_something;
> + * }
> + *
> + * static const TypeInfo my_type_info = {
> + *     .name = TYPE_MY,
> + *     .parent = TYPE_OBJECT,
> + *     .instance_size = sizeof(MyState),
> + *     .class_size = sizeof(MyClass),
> + *     .class_init = my_class_init,
> + * };
> + *
> + * typedef struct DerivedClass {
> + *     MyClass parent_class;
> + *
> + *     MyDoSomething parent_do_something;
> + * } MyClass;
> + *
> + * static void derived_do_something(MyState *obj)
> + * {
> + *     DerivedClass *dc = DERIVED_GET_CLASS(obj);
> + *
> + *     // do something here
> + *     dc->parent_do_something(obj);
> + *     // do something else here
> + * }
> + *
> + * static void derived_class_init(ObjectClass *oc, void *data)
> + * {
> + *     MyClass *mc = MY_CLASS(oc);
> + *     DerivedClass *dc = DERIVED_CLASS(oc);
> + *
> + *     dc->parent_do_something = mc->do_something;
> + *     mc->do_something = derived_do_something;
> + * }
> + *
> + * static const TypeInfo derived_type_info = {
> + *     .name = TYPE_DERIVED,
> + *     .parent = TYPE_MY,
> + *     .class_size = sizeof(DerivedClass),
> + *     .class_init = my_class_init,
> + * };
> + *   </programlisting>
> + * </example>
> + *
> + * Alternatively, object_class_by_name() can be used to obtain the class and
> + * its non-overridden methods for a specific type. This would correspond to
> + * |[ MyClass::method(...) ]| in C++.

I still wonder why resolving/saving/calling thie parent class method at
runtime (using any of the two methods described above) is better than
simply making the corresponding parent_class_method() function public,
so it can be called directly by classes that override the method.

Is there any use-case where resolving the parent class implementation at
runtime is really necessary?


> + *
> + * The first example of such a QOM method was #CPUClass.reset,
> + * another example is #DeviceClass.realize.
>   */
>  
>  
> -- 
> 1.7.10.4
>
Anthony Liguori - Jan. 17, 2013, 6:55 p.m.
Eduardo Habkost <ehabkost@redhat.com> writes:

> On Thu, Jan 17, 2013 at 08:31:50AM +0100, Andreas Färber wrote:
>> + * Alternatively, object_class_by_name() can be used to obtain the class and
>> + * its non-overridden methods for a specific type. This would correspond to
>> + * |[ MyClass::method(...) ]| in C++.
>
> I still wonder why resolving/saving/calling thie parent class method at
> runtime (using any of the two methods described above) is better than
> simply making the corresponding parent_class_method() function public,
> so it can be called directly by classes that override the method.

It's idiomatic from GObject.

I'm not sure I can come up with a concrete example but in the absense of
a compelling reason to shift from the idiom, I'd strongly suggest not.

Regards,

Anthony Liguori

>
> Is there any use-case where resolving the parent class implementation at
> runtime is really necessary?
>
>
>> + *
>> + * The first example of such a QOM method was #CPUClass.reset,
>> + * another example is #DeviceClass.realize.
>>   */
>>  
>>  
>> -- 
>> 1.7.10.4
>> 
>
> -- 
> Eduardo
Anthony Liguori - Jan. 20, 2013, 8:53 p.m.
Applied.  Thanks.

Regards,

Anthony Liguori

Patch

diff --git a/hw/qdev-core.h b/hw/qdev-core.h
index 3d75ae2..731aadd 100644
--- a/hw/qdev-core.h
+++ b/hw/qdev-core.h
@@ -60,14 +60,20 @@  struct VMStateDescription;
  * The @init callback is considered private to a particular bus implementation
  * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
  * "init" callback on their parent class instead.
+ *
  * Any type may override the @realize and/or @unrealize callbacks but needs
- * to call (and thus save) the parent type's implementation if so desired.
- * Usually this means storing the previous value of, e.g., @realized inside
- * the type's class structure and overwriting it with a function that first
- * invokes the stored callback, then performs any additional steps.
+ * to call the parent type's implementation if keeping their functionality
+ * is desired. Refer to QOM documentation for further discussion and examples.
+ *
+ * <note>
+ *   <para>
  * If a type derived directly from TYPE_DEVICE implements @realize, it does
  * not need to implement @init and therefore does not need to store and call
  * #DeviceClass' default @realize callback.
+ * For other types consult the documentation and implementation of the
+ * respective parent types.
+ *   </para>
+ * </note>
  */
 typedef struct DeviceClass {
     /*< private >*/
diff --git a/include/qom/object.h b/include/qom/object.h
index 1ef2f0e..8e16ea8 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -147,9 +147,9 @@  typedef struct InterfaceInfo InterfaceInfo;
  *   </programlisting>
  * </example>
  *
- * Introducing new virtual functions requires a class to define its own
- * struct and to add a .class_size member to the TypeInfo.  Each function
- * will also have a wrapper to call it easily:
+ * Introducing new virtual methods requires a class to define its own
+ * struct and to add a .class_size member to the #TypeInfo.  Each method
+ * will also have a wrapper function to call it easily:
  *
  * <example>
  *   <title>Defining an abstract class</title>
@@ -186,6 +186,104 @@  typedef struct InterfaceInfo InterfaceInfo;
  * similar to normal types except for the fact that are only defined by
  * their classes and never carry any state.  You can dynamically cast an object
  * to one of its #Interface types and vice versa.
+ *
+ * # Methods #
+ *
+ * A <emphasis>method</emphasis> is a function within the namespace scope of
+ * a class. It usually operates on the object instance by passing it as a
+ * strongly-typed first argument.
+ * If it does not operate on an object instance, it is dubbed
+ * <emphasis>class method</emphasis>.
+ *
+ * Methods cannot be overloaded. That is, the #ObjectClass and method name
+ * uniquely identity the function to be called; the signature does not vary
+ * except for trailing varargs.
+ *
+ * Methods are always <emphasis>virtual</emphasis>. Overriding a method in
+ * #TypeInfo.class_init of a subclass leads to any user of the class obtained
+ * via OBJECT_GET_CLASS() accessing the overridden function.
+ * The original function is not automatically invoked. It is the responsability
+ * of the overriding class to determine whether and when to invoke the method
+ * being overridden.
+ *
+ * To invoke the method being overridden, the preferred solution is to store
+ * the original value in the overriding class before overriding the method.
+ * This corresponds to |[ {super,base}.method(...) ]| in Java and C#
+ * respectively; this frees the overriding class from hardcoding its parent
+ * class, which someone might choose to change at some point.
+ *
+ * <example>
+ *   <title>Overriding a virtual method</title>
+ *   <programlisting>
+ * typedef struct MyState MyState;
+ *
+ * typedef void (*MyDoSomething)(MyState *obj);
+ *
+ * typedef struct MyClass {
+ *     ObjectClass parent_class;
+ *
+ *     MyDoSomething do_something;
+ * } MyClass;
+ *
+ * static void my_do_something(MyState *obj)
+ * {
+ *     // do something
+ * }
+ *
+ * static void my_class_init(ObjectClass *oc, void *data)
+ * {
+ *     MyClass *mc = MY_CLASS(oc);
+ *
+ *     mc->do_something = my_do_something;
+ * }
+ *
+ * static const TypeInfo my_type_info = {
+ *     .name = TYPE_MY,
+ *     .parent = TYPE_OBJECT,
+ *     .instance_size = sizeof(MyState),
+ *     .class_size = sizeof(MyClass),
+ *     .class_init = my_class_init,
+ * };
+ *
+ * typedef struct DerivedClass {
+ *     MyClass parent_class;
+ *
+ *     MyDoSomething parent_do_something;
+ * } MyClass;
+ *
+ * static void derived_do_something(MyState *obj)
+ * {
+ *     DerivedClass *dc = DERIVED_GET_CLASS(obj);
+ *
+ *     // do something here
+ *     dc->parent_do_something(obj);
+ *     // do something else here
+ * }
+ *
+ * static void derived_class_init(ObjectClass *oc, void *data)
+ * {
+ *     MyClass *mc = MY_CLASS(oc);
+ *     DerivedClass *dc = DERIVED_CLASS(oc);
+ *
+ *     dc->parent_do_something = mc->do_something;
+ *     mc->do_something = derived_do_something;
+ * }
+ *
+ * static const TypeInfo derived_type_info = {
+ *     .name = TYPE_DERIVED,
+ *     .parent = TYPE_MY,
+ *     .class_size = sizeof(DerivedClass),
+ *     .class_init = my_class_init,
+ * };
+ *   </programlisting>
+ * </example>
+ *
+ * Alternatively, object_class_by_name() can be used to obtain the class and
+ * its non-overridden methods for a specific type. This would correspond to
+ * |[ MyClass::method(...) ]| in C++.
+ *
+ * The first example of such a QOM method was #CPUClass.reset,
+ * another example is #DeviceClass.realize.
  */