Re: simplifying closures



> 
> Hi,
> 
> So to summarize succintly what I just argued in more detail:

Yeah, I think you definitely started your arguments in the wrong 
foot.  You attacked the premise on the basis of memory where I
am afraid chaining always loses because every time you need to chain 
your memory size doubles.  It also creates a very large web of dependencies
in the chains with becomes fragle and hard to deal with.


The real question is what are the possible reasons for rewritting 
the gtk+ system in the first place.  Here is my summary of the reasoning.

  1) Make LB less of second class citizens.
     - All APIs work in terms of closures
     - structures passed through APIs hold closures and not function
       pointers.

  2) Give the same separation of connection and the flexiblity it
     allows to the C programmers.
     - gtk_signal_connect and varients exist in gtk+ for historic
       reasons.  
     - closures are the mechanism of glib.
     - C programmers learn closures,
     - closures are equal in every way to a function pointer.
       (copyable and resable)
     - closures should meet most practical needs for their concept.

Now I would argue that to meet number 1, your really have to suceed
well in number 2.  That is that if the closure API isn't good enough
for the C programmers to use then they won't use it.  And since 
LB need the closures they need the API's to think in terms of closures
otherwise LB will find the vast majority of the structures using
and passing around function pointers.  Thus the quality of the API
if closures aren't useful to C programmers will be low to LB.
 

Just to give a concrete example of why I say this.  Consider
libglade.  In libglade there is an autobind feature so that the 
C programmers don't have to cast through the structure and
thus know the whole XML tree to get the callbacks assigned.  
If they have to cast through the whole tree, they are tying themselves
to a specific version of that XML tree.  (It is also ugly as hell,
but we will skip that for now.)  As autobind doesn't work for
LB that means all LB must pass an SPI on to their users where
the have to connect up everything by hand.  Or they have
to write their own causing the LB to fracture farther from
the defective C API. 

However, if closures became a primary concept for both C and LB then
I could write the API like this....  (not totally correct, but
you get the picture.)


   GtkXML* xml=gtk_xml_new();

   /* set up a pool of symbolic closures to bind to */
   gtk_xml_add("open",g_closure_new(&function1,data1));
   gtk_xml_add("help",g_closure_object_new(help_dialog,&gtk_widget_show));
   gtk_xml_add("close",g_closure_new(&function3,data3));
   gtk_xml_add("new_file",g_closure_full_new(&function1,
                                             g_strdup("file"),
                                             &g_closure_free_data));

   /* load the xml which binds the names symbolicly */
   gtk_xml_load("my.xml");

   /* connect remaining closures using C magic */
   gtk_xml_autobind();  

Now if there were 5 widgets which could send "open" they all get
hooked up to the same closure.  Closures are objects which act
just like little private environments for the C functions.  Further,
notice everything in this API works great for LB save for the 
autobind.  Now if the XML tree changes I don't have to change
my code to know where all the widgets I wanted to hook up were located.
LB and C are more or less on the same footing and it allowed the
C writter to hide his function names and types.  In other words
both benifit.


I would go on to say that your arguments about chaining being easier
and on whether C programmers need to learn about the inotify and 
dnoticy are really moot.  They are necessary concepts where they 
are 1 or many.  I originally only planned to have one list but Tim pointed
out that there really must be two types.  


Now on to specific claims.

>  - I'm claiming that making closures a general-purpose feature for C
>    programmers is the only possible motivation for features such as
>    multiple user data, multiple connections, etc.; these features
>    aren't needed for language bindings.

Generally I agree here.  Language bindings can live with the 
( 1 invalid, 1 dtor) system.  However, this means the C widget
writer must know that the hell the internals are and at the
same time must know how to sucessfully chain them.  I can see
the fun if someone assumes they can use some internal and then
that internal gets taken by the language binder.  Allow an arbitrary
number and the users doesn't need to peek in to see if some
else has used the resource up.


>  - we haven't actually mapped out when C programmers are going to 
>    use these features, how they will use them, etc. i.e. 
>    we seem to be starting with an implementation and not 
>    by outlining the use cases and the API that would be convenient in 
>    those cases.

I provided the first map to Tim and Owen.  However, as my map 
was not close to the final one, I didn't feel it was a good idea to
release it.  Tim is just now got the ideas straightened out enough
to say waht a clousre system needs to have in terms of internals. 

My argument on when and where are C users are going to use closures
is simple "everywhere that they would be inclined to pass a function
pointer".  If they don't do that then the system won't work for LB.



> I'd like to start over on the closure thing, and from an
> end-programmer perspective, see convincing evidence that someone will
> use these features.

Start over on the closure implementation or the discussion? 
Who will be the judge the merits?  You?  Me?  Tim?  Considering
my ablity to convince you of anything I think I would rather take
chances with a firing squad. ;-)


Look I have been doing closures for over a year now.  It is really hard
to get people to discuss it because it is to most people voodoo.  I
sent out nearly a constant stream of mail asking for advice and
feedback when I created libsigc++ and got very little.  Basically,
getting people to up front discuss this kind of API will only happen
under threat.  Only after I released it and users used it for
many months did I get the kind of feedback to tell me I made the
wrong choice on chaining and other issues.   Closures aren't 
sexy and are the utter guts of a system.  Their importance to the overall
design is far greater than the interest they generate.  So basically
it will be you, Owen, Tim and myslef that place any input into this
at all. 

You argument of why we would never use it in C is just like that when I 
proposed libsigc++ to Qt.  They said we have a simpler system which 
only allowed direct connections.  They looked at the code base and don't 
see where it would get used as anything else.  What the missed is all
the places where the implemented a complex API to get around the limitation
and thus the limitation is no longer apparent.

Time and again I look at what people do with gtk--/libsigc++ code
and I am surprised.  They build event queues and multitheading systems.
They wanted to copy them.  At the same time I have found in gtk-- code,
it openned up a whole basket of things which made the design simpler I 
didn't see when I created the system.  It solved may of the problems
I have previously considered impossible.


> Also, the GClosure object and API seem low level and difficult to
> understand if it's supposed to be an end-programmer API. Invalidity
> notification vs. destroy notification, adding multiple data by
> creating a derived struct, etc. is pretty intimidating stuff.  People
> don't understand the existing signal_connect() variants.

This is a reasonably good argument, but will apply no mater how
many notifications or destroy functions we allow.  Tim has sucessful
argued to me there must be 2 types and I think his reasoning is sound. 
Thus the any functioning closure API must have that.  If the C
widget writter must know how to deal with closures to make good
LB workable code, the API must be explainable in a short tutorial
and must make sense.  To the average library users connections are 
largely balck box though so just telling them these functions make 
closures which are "function objects" which you can pass and be called 
back later is more that enough.

--Karl 




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