Re: Proposal: Ref Counting Conventions



Miguel de Icaza <miguel@helixcode.com> writes:

>
> Thanks for pointing this out.  Can you file a bug report for Bonobo in
> this case, or better yet, submit a bug report?

I assume you meant "a patch". I'd be glad to fix all Bonobo methods
that return Bonobo objects to ref them first if you agreeit is the
right thing to do. Maybe Michael can help, since he is the one who
brought this convention to our attention.

> 
> > What would you propose as an alternate convention for inout
> > parameters? I think the idea here is supposed to be that you can treat
> > what you get back as functionally equivalent to what you passed in,
> > whether or not it actaully got replaced by a different object. This
> > actually even makes sense if you were holding multiple refs to the
> > original object.
> 
> Proposal:
> 
> 	inout parameters should be treated just like an in parameter
> 	and an out parameter.
> 
> 	This means: no special unrefing of the object you get passed
> 	to.
> 
> Reply to the original proposal and sort of rationale:
> 
> An out parameter just happens to be an extra return value that
> syntactically does not look as cute as:
> 
> 	x = fn ();
> 
> It is just:
> 
> 	fn (&x);
> 
> The problem is that you pass some data *in* and then get some data
> *out*.  inout is just an implementation trick to provide the illusion
> of "efficiency", because "void x (inout Object a)" is nothing more
> than: "void fn (in Object a, out Object b)", or to use the example above: 
> "Object fn (in Object a)".  
> 
> Unrefing your first argument in this case is obviously broken[1],
> because then every invocation to a method should become (for simetry): 
> 
> 	x_ref (a);
> 	x_op (a, &ev);
> 
> Every single one of them.  Because semantically it is the same thing
> you propose.

Note that I didn't propose it. I was just following up to Mike's
posting that proposed following the Microsoft convention.

I think the idea here is that one common case is that you return the
same out thing through the inout parameter that you took in. In this
case, ref()ing it is kind of stupid, because that usually means the
client code will just have to immediately unref. So if you don't ref
the argument on inout when you take the same object in and out, the
semantically analogous thing for the case where you take different
objects in and out is to unref the in object and ref the out object.

Please at least try to understand the rationale before panning it.
Let me try to give another example:


{
  Some_Object a;
  Another_Object b;
  
  Some_Object_change_or_replace_another (a, &b);
  
  // If the value of b is not changed, we don't want an extra ref,
  // otherwise we have to unref immediately.
  // 
  // If the value of b _is_ changed, we have just dropped the old b on the floor.
  // We had better have gotten a ref on the new b, but we still need to unref 
  // the old b somehow.
  //
  // But this works perfectly with the inout convention Michael
  // described.  If b is unchanged, we have the same number of
  // refs. If it is changed, we lose the ref on the old b, and gain a
  // ref on the new b, which is exactly what we want.
}

// So to get it right without the inout convention Michael described, you
// have to actually do this:

{
  Some_Object a;
  Another_Object b;
  Another_Object tmp;
  
  tmp = b;
  Some_Object_change_or_replace_another (a, &b);
  Another_Object_unref (tmp);
  
  // much uglier than the last version
}



If you try to ref the results passed out through the inout argument
only if it is different, things get even uglier.

So basically for reasons of convention and syntax, treating an inout
argument just like separate in and out arguments is not the most
convenient thing.


> An alternate convention is required here (saying "varies on the docs"
> is a valid answer).
> 

Yeah, just like the meaning of `const' in the Gtk/GNOME API varies
according to the docs.

> > Having and following conventions is still very useful even if you have
> > docs and ref leak detection code (although how to do the latter is a
> > mystery to me; it seems like a distributed GC problem). 
> 
> Not really.  You just need to be able to trace ref/unrefs.  And write
> some tools to manipulate data generated from a debugging run.  Sure,
> not the perfect solution, but much better than a semi-broken
> convention.

I can imagine doing it with some sort of logging scheme, but it is
certainly non-trivial. In any case, such a system is complementary to
a convention that makes it more likely you will get code right on the
first try, not a replacement for it.

> Speaking of which, what is the Microsoft standard for this, is there
> any?
> 

For what - ref/unref tracing? I don't know. I have certainly seen
Windows-based developers sink ridiculous amounts of time into
refcounting bugs before. Which proves that no convention or tool is a
satisfactory replacement for a brain.

> > For what it's worth, the conventions Mike described are the ones
> > typically used with COM. They were developed over the course of long
> > practical experience and work pretty well in most situations.
> 
> The inout is not part of any spec I can find in my COM books that i
> have here, and I would doubt that they did something as stupid as
> unrefing an in parameter for the inout case.  And if they did, then I
> would agree with some people that some Microsoft hackers do stupid
> things. 

Whatever their faults may be, Microsoft has deployed many more
components into production use than all of use here put
together. While we should not follow what they do blindly, we should
at least look closely at their reasoning before we dismiss it.


BTW, I find it really bizzare that I am defending a Microsoft practice
to Miguel here. Isn't it supposed to be the other way around? Has the
whole world gone mad? :-)

 - Maciej




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