|
Boost : |
From: Jody Hagins (jody-boost-011304_at_[hidden])
Date: 2005-02-24 22:29:02
Warning: This is a fairly lengthy post, as I have had a difficult time
putting my thoughts into words (also, I have had very little free time
lately -- though it is hard to say that with a straight face since I
just spent the holiday weekend skiiing). If you want to skip my
monotonous musings, read the summary only, and possibly skip down a few
paragraphs until you see a significant amout of vertical white space,
then read some more technical points.
I would really appreciate any thoughts or insights, as I am quite
frankly not very satisfied with my own.
SUMMARY: I would like to delay proposing a typeid() replacement.
Instead, I'd like to submit my testsuite, and ask people to run it on
various platforms and report the results. This will help us decide how
best to approach this seemingly simple, but very difficult, subject. I
would like to propose a boost::type_info class now (or very soon).
Meaningful instances of boost::type_info will be constructed from a
std::type_info resulting from a native typeid() call. Once we figure
out what route to take wrt typeid(), then I think it can be used in a
very straight forward manner.
Now for some rumblings, where I try to sort out my experiences with
typeid (I apologize in advance for the lack of polish, but I want to get
this out for comment because I am going out of town Friday afternoon,
and will not be back until Sunday night).
A while back, I had some of my own code to use typeid/type_info. The
code was inspired by the TypeInfo class in "Modern C++ Design" by Andrei
Alexandrescu. However, I ran into some issues (namely the infamous g++
shared library problem). A search of boost found an implementation in
Boost.Python.
As has been mentioned in the past, this seems like a useful utility to
have around, so I made an attempt to bring it out of Boost.Python, and
give it life of its own. David suggested that such a small exposure is
a good candidate for a fast track review, so I naively thought that
meant it would be a small amount of work.
Along the way, I ran into several portability issues, and decided to
make sure the code had the best typeid/type_info support I could
imagine. Unfortunately, this took me down a very twisted highway. I
could not find an existing test suite, so I wrote my own, based on the
standard (5.2.8 and 18.5.1). Well, this turned into a nightmare,
because I have had a hard time finding any compiler that will pass all
my tests. I have had to move to gcc 3.4 to get most of them to pass,
and still some fail (though it may be due to my tests... I am still
looking into that). I will say that I now know more about typeid() than
I ever thought I'd want to know (I could quite possibly quote verbatum
section 5.2.8, and a fair bit of 18.5.1 to boot).
Anyway, getting a portable typeid/type_info library working is not
exactly as easy as it appears. A previous post of mine attributes most
typeid problems to older msvc/intel compilers. This is only mostly
true. They are the worst, because they do not even try to remove the
top-level cv-qualifiers. However, even relatively recent versions of
gcc has had problems with this in esoteric cases (multidimensional array
with cv qualifiers mixed with typedefs).
All this to say that I have my doubts that many compilers fully support
typeid() correctly. To top it all off, many implementations have
trouble honoring the comparison mechanism across separate shared
libraries (as noted in the Boost.Python implementation), so there are
some workarounds needed for type_info as well.
Since I have seen so many problems, I am no longer certain that the
review of typeid can be done quickly. While the implementation in
Boost.Python works well, it also has several holes, so I do not think it
wise to simply "bring it out" into boost. Thus, I have made an attempt
to "industrialize" it. With this in mind, I thought I'd give a rundown
of the major issues. I recently posted some of my concerns, but due to
the length of that post, and possibly its ramblings, I have not seen any
replies. Yes, I know, this one is longer, and possibly more "rambling"
but I am hopeful yet ;-)
I will leave the more minor issues for later, but would really like some
input on the bigger ones.
The library, as used in Boost.Python, relies on calling the no-parameter
template function, type_id, to get the type info object. Use of
typeid() by itself is absent, because of the problem with compilers
getting the typeid() implementation correct. For example:
struct foo { /* ... */ };
boost::python::type_info ti = boost::python::type_id< foo >();
Unfortunately, boost::python::type_id<>() has a couple major drawbacks
(and a number of "minor" ones).
1. It only supports type-id calls, with a specific type passed as a
template parameter. The ability to compute type_info based on the
result of an expression is scant (a bit more functionality can possibly
be obtained with more tricks like the ingenious typeof() stuff recently
posted).
2. To add support for expressions and lvalues, overloads of type_id()
can be provided. This works reasonably well (with enough machinery to
get around compiler problems), but the spec for typeid() says that the
expression is not supposed to be evaluated (unless the expression is an
lvalue of a polymorphic type, or dereferences a pointer to a polymorphic
type). I have yet to see a way to call a function and prevent the
expression from being evaluated (maybe with some modern tricks and
is_polymorphic -- but we are then probably leaving several compilers
behind as well). Also, I have been unable to get the "workaround" to
throw std::bad_typeid when dereferencing a null pointer, as specified in
5.2.8.2).
3. For compilers with bad cv-qualifier support wrt typeid(), it requires
a fair amount of machinery to get rid of the cv-qualifiers.
Unfortunately, the same machinery makes it difficult to preserve the
polymorphic requirements of 5.2.8.2, and I have yet to find the right
code to get this to work (though I think it may be possible).
Thus, we face a dilemma. Either always use the native typeid(), knowing
that your compiler may not fully support it "by the book" or provide
some workaround, that will not provide everything either. By fixing
some things, others are broken. We are left with some options:
1. Always use the native typeid() in code, and live with what the
compiler does.
2. Always use a "workaround" and live with whatever level of "brokeness"
that provides. I am not convinced that we can get a consistent level of
brokeness for all compilers, though it is more likely to be close for
all compilers than just using typeid().
3. Provide a macro BOOST_TYPEID(), which is set depending on which
compiler is being used, to get the "best" effect.
Depending on the day, I feel differently about which option I like.
Thus, I have written a fairly extensive set of tests for native
typeid(). I feel fairly certain that they can tell us what to expect
from any compiler relative to typeid conformance. We could use those
tests results, from "all" the supported platforms to see where we are
(my access to compilers/platforms is quite limited). Maybe if we had a
better idea about what each of the "major" platoforms do/not support we
could get a better idea as to how we want to proceed. In any case, I do
not think this will be super quick.
So, let's move to type_info. I think this one is a bit more clear
(though we still need some compiler workarounds). However, the only
real workarounds I have found so far involve "broken" comparison
operators. I think these are fairly well known, and mostly solved. I
also have a fairly extensive set of tests for native std::type_info, as
well as the new boost::type_info. However, I am still hung up on the
whole typeid thing stated above.
I tend to think that most use of typeid() will work as expected. The
"major" problems concern quite old compilers (I think), and some of the
problems in more modern compilers are in the "corners" of usage. Thus,
it makes sense to get boost::type_info in place, and wait until we have
some test results to see what is the propor course of action for typeid.
Thanks, and if you read this far, maybe YOU should go skiing ;-)
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk