[ROOT] I/O registration

From: George A. Heintzelman (gah@bnl.gov)
Date: Wed Nov 08 2000 - 19:36:27 MET


Hi Rooters,

It seems right now very difficult to implement a 'private class' idiom 
in ROOT I/O. The basic idea is encapsulation, and is referred to by 
some as the 'Pimpl' idiom; it's much in favor in programming circles. 
Here's what you do to get this:

// header file

class X {
private:
	class Impl; // declared but not defined.
	Impl * pImpl;

// method declarations -- not definitions.

}

// Implementation file

class X::Impl {
	// Define the Implementation class.
}

void X::SomeMethod() {
	return pImpl->SomeMethod();
}

You don't have to go whole-hog on this kind of idiom for it to be 
useful. For example, you may want to encapsulate the structure of a 
particular data structure, if that structure is only referred to in the 
privacy of the internal definitions, but leave some things in the 
header which need to be referred to quickly in inline functions. 
Naturally, using the idiom can have its efficiency prices; but assume 
you are willing to pay those prices for what you dealing with.

Now, the problem is that, as far as I can tell, in order to 
successfully stream the implementation objects in this idiom, they have 
to be declared and visible to CINT, even if they derive from TObject 
and I define my own Streamer (obviously I can't have CINT generate it 
if it doesn't know about it, that doesn't bother me). Looking into the 
guts of ROOT, it looks like the fundamental reason for this is just 
one: ReadObject needs to be able to call the TClass::New for the class, 
and TClass::New gets its info from CINT (only). This can get 
particularly annoying for template classes which you have to link into 
CINT even though the command line user has no need whatever to know 
about them.

So what I would propose is that there be a way to register a 
non-CINT-calling functor object for TClass:New(), using the CINT 
ClassInfo::New() by default but letting the user override it. (If I 
were writing ROOT I/O from scratch, this is what I would require to 
register a class with the I/O system.) This mechanism could also be 
used to minimize CINT-parsing needed in some cases. It would have the 
side advantage as well of allowing a user to not create a public 
default constructor for a streamed object, if they tell ROOT instead 
how to create the 'blank' object it needs to call the Streamer on. 
Finally, it would allow you to pull off some currently impossible dirty 
tricks like changing a persistent class's name -- you define just an 
empty class of the old name, and in its TClass:New functor create 
instead an object with the new class's name (being careful with version 
numbering, of course).

With proper defaults getting set up, this would be entirely transparent 
and backwards compatible.

So, what do you guys say about doing this?

George Heintzelman
gah@bnl.gov



This archive was generated by hypermail 2b29 : Tue Jan 02 2001 - 11:50:36 MET