Re: Type checking



On Thu, 2010-03-18 at 09:03 +1100, Andrew Cowie wrote:

> I've often wondered about it, because on the one hand we have 
> 
>         void
>         gtk_button_set_label (GtkButton   *button,
>         		      const gchar *label)
>         {
>           g_return_if_fail (GTK_IS_BUTTON (button));
>         
> in gtk/gtkbutton.c which after wading through several macros ends up as
> a call to g_type_check_instance() in glib/gtype.c with some if/else
> blocks around it.

the G_TYPE_CHECK_INSTANCE_TYPE() macro won't be disabled - ever. the
only way to disable that particular type check is to compile with
-DG_DISABLE_CHECKS, which disables g_return_*() -- and you don't really
want to do that.

> Meanwhile most of the time (in C anyway) people call 
> 
>         gtk_button_set_label(GTK_BUTTON(button), "Hello World");

which can be disabled by using -DG_DISABLE_CAST_CHECKS, resulting in:

  #define GTK_BUTTON(obj)	((GtkButton *) (obj))

a plain, unchecked C cast.

> and it's been working for us because a) we have correct type information
> so we're casting the right thing anyway, and b) because the first thing
> the functions we are calling do is check the type of the inbound
> pointer.

that's something only a binding could do - but only certain bindings can
actually offer this degree of type checking. for most dynamic languages
out there, the actual type check should be deferred to GObject.

> So maybe we can at least not check in the cast macros?

again, -DG_DISABLE_CAST_CHECKS does that.

surrendering type checking in a run-time type system is giving up the
little slice of safety it guarantees. we do type checking on both ends
because we don't know what's been fed to the public API; private API
should not have type checks (but they should assert() if the internal
state is screwed). a stop gap solution is to avoid doing crazy stuff
like:

  static void
  my_blah_widget_init (MyBlahWidget *widget)
  {
    gtk_widget_set_foo (GTK_WIDGET (widget), TRUE);
    gtk_widget_set_bar (GTK_WIDGET (widget), FALSE);
    gtk_widget_set_baz (GTK_WIDGET (widget), 42);
  }

and do one since cast instead:

  static void
  my_blah_widget_init (MyBlahWidget *widget)
  {
    GtkWidget *w = GTK_WIDGET (widget);

    gtk_widget_set_foo (w, TRUE);
    gtk_widget_set_bar (w, FALSE);
    gtk_widget_set_baz (w, 42);
  }

the real solution, though obviously more involved, is to make type
checking faster; it's a common operation, so shaving 50% off would
result in an overall benefit for everyone. the recent fixes Alexander
wrote and that went into making type checks on interfaces an O(1)
operation are a step in the right direction, especially for libraries
that use interfaces a lot.

ciao,
 Emmanuele.

-- 
W: http://www.emmanuelebassi.name
B: http://blogs.gnome.org/ebassi



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