Re: GError



On 23 Jun 2000, Havoc Pennington wrote:

> 
> Tim Janik <timj@gtk.org> writes: 
> > to avoid that, i personally prefer the simply way of simply having
> > GError { GQuark domain; gint code; gchar *blurb; } and drop the user
> > data idea alltogether which unavoidedly comes with copy/free/whack_me/whatnot
> > complexity.
> > 
> 
> We were only very slightly leaning toward including the user_data, so
> I can be convinced of this probably.

huh, that email was 9k already ;)

ok, to summarize:

- gpointer user_data; almost always isn't enough, at the point where
  you consider adding user_data, you can almost always consider multiple
  entities adding data as well. rule of thumb: never use gpointer user_data;
  but GData *qdata; if at all (this is still outstanding for Gdk objects, btw)
- the right thing to do for error reporting can be almost anything, depending
  on where you want it to apply. to find a generic solution to this that is
  flexible enough for all required purposes is extremely hard if not
  impossible. definitely not doable without a significant amount of complexity
  though
- for the most cases, a simple error code and a blurb string (if that's really
  required - with our enum parser we can even generate code->string lookups
  extremely easily) is sufficient. more complex scenarios are definitely
  possible, but quite rare and usually do better with a specific anyway
- for the purpose of glib, where we try to 1) cover glib/gtk internal needs,
  2) provide convenience interfaces for C programmers, gint+gchar* is
  definitely good enough and gives programmers a clean and easy interface
  that's adequat for most cases
- skipping the user_data approach gets rid of a lot of uglieness in the
  proposed API. since you want to feature error codes as aditional function
  arguments (as opposed to pure return values) you'll either have to deal
  with a structure to be filled in, or a pointer to be filled in. believe
  it or not, &data is generally easier to handle (for humans) than
  data && *data.
- user_data forces us to provide customized free and copy functions. i
  personally, when wanting to report my open() failed error, don't want to
  bother implementing copy/free functions, and don't want to be forced
  checking multiple NULL levels when setting my error value:
  my_open (gchar *filename, GError **err) {
    if (err && *err) g_error_set (*err, "foo"); }

of course we need to be fair here, so the advantages aparent to me are:

- GError with user data will scale to future needs i may have, such as
  passing stamps/parser-lines/etc. around. though, that's best done
  with GData, so scaling isn't limited to one level, and i don't need to
  handle (code) a huge bunch of error-specifc customized accessors
  get_stamp()/get_parser_line()/get_etc()
- GError being adaptable to more complex report situations saves me
  from needing to reinvent problem-specific error report mechanisms


but my baseline is, if you really need to carry more data around, you
actually _are_ better off, doing your own special thing. such as passing
a GString *warning_recorder; into a parsing function, or passing
a stamp around if you need that. i wouldn't bother extending the
GError structure (or cook up a user_data structure) to pass that info
around, mostly because specialized error information normaly doesn't
even need to be passed around for more than one or two levels of
function calls anyways (that's because the intermediate functions
have to be error aware anyways, since we can't abort across multiple
call levels in C and have the GC clean up after us).


that, and the obvious simplification (and cleanlyness, as
g_error_*() actually operates on GError*) in the GError API:

  static can_error (..., GError *error) {
    g_error_set (error, "i'm ok");
  }
  GError error = { 0, }; /* or GError error = G_ERROR_INIT; as owen prefers */
  can_error (..., &error);
  if (g_error_match (&error, 42)) ...

as opposed to

  can_error (..., GError **error) {
    if (error) g_error_set (*error, "i'm ok");
  }
  GError *error = NULL;
  can_error (..., &error);
  if (error && g_error_match (error, 42)) ...


really makes me believe that user_data isn't worth it (especially
since i consider that a rarely used feature).

and yes, you can hide the above 'if (error' in the latter example in
g_error_match(), but that's not very intuitive anymore:
"is g_error_match() operating on the pointer now? or on the structure?
 or does it consider NULL pointers as an OK error? where are those
 reference docs people keep talking about... heck, i just pass in
 a gint *error_code;"


ok, so i think i've made my standpoint clear on that issue. the decision
is up to you, i don't feel too strong on this. i guess i'll just not use
GError if i find it unintuitive ;)



one last note on new/free/create/etc...

i have a strong association with alloc() in terms of free(), like
probably most C programmers (if you are a C programmer and you don't
feel like this, look behind you, you're leaking as hell ;).
and once you've been exposed to c++ or similar languages, you better
keep in mind to "delete" "new"ed structures, instead of "free"ing them,
which is why i don't like new+free very much. so do:

  new + destroy	or
  new + ref + unref or
  alloc + free


when it comes to automatic allocations on the stack, sometimes
in combination with _init, i.e.
  
  GError error = { 0, }; or
  GError error = G_ERROR_INIT; or
  GError error; g_error_init (&error);

i won't mix that with any of the above destroy/unref/free, rather,
structures that got simply _initialized_, with their allocation
pattern being _opaque_ (or _automatic_) to the programmer, should
obviously get _uninitialized_ and be release _opaquely_ (or
_automatic_) as well:

  g_error_unset (&error); or
  g_error_free_contents (&error); or
  g_error_uninit (&error);

though _free_contents() is somewhat lengthy, and _uninit() doesn't
feel like a real word (i'm only german though), so i usually use
_unset().


> 
> Havoc
> 

---
ciaoTJ





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