Re: Varargs type stringification (#50972)

On 1 Apr 2001, Owen Taylor wrote:

> Tim Janik <timj gtk org> writes:
> > On 27 Mar 2001, Owen Taylor wrote:
> > 
> > > 
> > > g_strdup_value_contents() is neat, but not all that convenient to 
> > > use since:
> > > 
> > >  - You have to construct a value if you don't 
> > 
> > don't ... what? 
> To fill in the (fairly obvious) blank - if you don't already have
> one. The most common cases where this would be useful:
>  - To print out an enum value
>  - To print out a flags value
>  - To print out a GObject pointer with the type
> > it strngifies a value's contents, i don't quite understand why you would
> > want this to work for non-GValue varargs collected values... ;)
> Read the bug report. Basically, the original idea was that
> we wanted an easy way to print out an enumeration as a string
> for debug purposes.
>  G_CONST_RETURN gchar *gtk_enum_get_name (GType enum_type, guint value);

wait, you muddle things up here.
the bug report talks about:

  G_CONST_RETURN g_enum_get_value_name (GType enum_type, gint value);
(missing gchar*)

eventhough havoc claims to be able to implement that single handedly,
it can't be implemented via constant returns, because class names
are only accesible as long as the class is, which is why the current

GEnumValue*     g_enum_get_value                (GEnumClass     *enum_class,
                                                 gint            value);

takes a class pointer. OTOH, the variant you mention:

  G_CONST_RETURN gchar* gtk_enum_get_name (GType enum_type, guint value);

could be implemented if it internally used gtk_type_class, since that
makes classes static nevertheless.

(and an aside to havoc, your intial stab at g_strdup_value_contents() did
 something like:
 GEnumClass *class = g_type_class_peek (enum_type);
 eval (class->values[enum_value].value_name);
 this could never work, for two reasons, once you have enum_type, you
 don't necessarily get an initialized class from g_type_class_peek(),
 only g_type_class_ref() gives you that.
 also, think about an enum:
 typedef enum { FOO = 1, BAR = 31476518 } MyEnum;
 you don't really expect GEnumClass to have an array with that many
 elements, do you? ;)

> But it seemed to me that it might be better to provide something
> more general.
> > > Here's a patch to add:
> > > 
> > > gchar*                g_strdup_type             (GType         type,
> > > 					         ...);
> > 
> > erm, "type" appears really odd to me, probably better called
> > g_strdup_typed_value(), but before that i'd like to hear some
> > rationale for that function.
> > 
> > > G_CONST_RETURN char * g_stringify_type          (GType         type,
> > > 					         ...);
> > > 
> > > Which do the same thing but with GType + varargs. g_stringfy_type()
> > > uses a small ring buffer of static results to make it real easy
> > > to use in debug printfs.
> > 
> > urg, this is a rather cruel hack. while i understand the need for the
> > added convenience, we have the same problem (inconvenience) in a couple
> > other places as well (the most prominent probably being g_strdup_printf()).
> I don't see g_strdup_printf() as being at all parallel.

well, i use:

gchar *string = g_strdup_printf (...);
g_print ("...%s...", string);
g_free (string);

far more frequently than g_strdup_value_contents(), so the parallel here
is obvious to me.

> > i'd rather avoid having ring-buffer variants sprang up for all of them
> > during future development and provide something more suitable and scalable
> > for long-term use. on why i consider ring-buffer backends not-scalable,
> > if functions with ring-buffer backends are called more than ring_size
> > times from a function, presumably "constant" strings suddenly become
> > invalid. you might want to say that with ring size of e.g. 16, this is
> > unlikely to be triggered by code that uses those functions only for
> > debugging output, but:
> > 
> > people don't use your code only for purposes you had in mind, or, more
> > conretely, you can't assure g_stringify_typed_value() is only being used
> > for debugging output, or only for printfs with less than ring-size
> > arguments. especially with setups like:
> >   strvalue = g_stringify_typed_value (&my_value);
> >   third_party_library_call_that_might_use_g_stringify_typed_value_also ();
> >   printf ("%s\n", strvalue);
> > users will have to be aware that g_stringify_typed_value() uses a
> > ring-buffer backend, i.e. that it doesn't really return a
> > G_CONST_RETURN string, and how big the ring buffer is. as soon as
> > we add more "convenience" functions to our API that also uses ring buffers,
> > preferrable with different sizes even ;) we'll be right on track to win
> > the most-confusing-API award.
> Well, note that my patch for g_stringify_type() actually had docs with
> the appropriate warnings...
> I agree that it is somewhat dangerous. I don't see it as leading to
> the rack-and-ruin as you seem to see it leading to. After all the C
> library has had functions in it that use only a _single_ static buffer
> for a long time.

which is an entirely different matter, i've always been willing to add
functions to gtk that would return from a single static buffer, simply
because that's an established concept in libc, but so far you were
against them and so our code has stayed clean from such things (which
in the end, i don't regret really).

> We could call it g_debug_stringify_type() or something like that if
> you want the name to more explicitely indicate the use.

if you really want that to be used in debug functions only and not
for production, i wonder why you worry about releasing the string
at all ;)

> Of course, the nice thing to do here would be to be able to insert
> typed values as a special format specifier into g_print() /
> g_strdup_printf(), but reimplementing printf() is not high on my list
> of things to do....

hum, i guess we need to talk a bit ;)
inventing new printf() format identifiers shouldn't constitute our
day-to-day work.

> > a good while back i already spent a couple thoughts on getting around
> > the need to free certain temporary values (mostly strings) and how to
> > provide a suitable g_alloca() implementation for systems where we can't
> > use native alloca() for whatever reasons.
> Returning result allocated through alloca() is something that you
> _really_ should not do. It's not safe at all.

lemme think...
would i do that? no
did i suggest that? no
but thanks anyway for the clever advice.

> So, I don't see any way (without statement expressions, and not really
> even then) of writing something that works inline using alloca. And
> once you've given up the ability to write things inline, I think
> explicit deallocation is best.
> > i think the best approach for both is a stack-level dependant allocator
> > that's undergoing frequent release cycles triggered by the main loop.
> Sounds scary.

i expected a comment like that which is why i'd like to generally sit
down with you and talk about such a thing (in the end it comes close
to some pseudo-GC thingy which is more in your domain than mine) as
i wrote further down.

> And actually, I don't think using main-loop triggered deallocation is
> really safe, since people may write apps that do arbitrary amounts of
> operations before returning to the main loop.

that is right, depending on the usage pattern however, both can
badly bite us wrg defered freeing, ring-buffer returns and stack-level
based collection. i don't think i need to make up a usage case where
a ring-buffer will perform worse, it's as easy as coming up with a case
where stack-level dependant collection performs worse.

> > i'd like to defer discussion about such allocators a bit though, say
> > untill next week, where we hopefully have a chance to dicuss that in person.
> A post 2.0 thing, I believe.

i'd think so as well, unless you intend to persue constant returns
for g_strdup_value_contents().
in any case, we should at least defer that untill thursday where
we can take that out like real men, with real fists and blood and
stuff ;)

>                                         Owen


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