HiveBrain v1.2.0
Get Started
← Back to all entries
gotchacppCritical

Why does C++ not have reflection?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
havewhydoesreflectionnot

Problem

This is a somewhat bizarre question. My objectives are to understand the language design decision and to identify the possibilities of reflection in C++.

-
Why C++ language committee did not go towards implementing reflection in the language? Is reflection too difficult in a language that does not run on a virtual machine (like java)?

-
If one were to implement reflection for C++, what will be the challenges?

I guess the uses of reflection are well-known: editors can be more easily written, program code will be smaller, mocks can be generated for unit tests and so on. But it would be great if you could comment on uses of reflection too.

Solution

There are several problems with reflection in C++.

-
It's a lot of work to add, and the C++ committee is fairly conservative, and don't spend time on radical new features unless they're sure it'll pay off. (A suggestion for adding a module system similar to .NET assemblies has been made, and while I think there's general consensus that it'd be nice to have, it's not their top priority at the moment, and has been pushed back until well after C++0x. The motivation for this feature is to get rid of the #include system, but it would also enable at least some metadata).

-
You don't pay for what you don't
use. That's one of the must basic
design philosophies underlying C++.
Why should my code carry around
metadata if I may never need it?
Moreover, the addition of metadata
may inhibit the compiler from
optimizing. Why should I pay that
cost in my code if I may never need
that metadata?

-
Which leads us to another big point:
C++ makes very few guarantees
about the compiled code. The
compiler is allowed to do pretty
much anything it likes, as long as
the resulting functionality is what
is expected. For example, your
classes aren't required to actually
be there. The compiler can optimize them away, inline
everything they do, and it
frequently does just that, because
even simple template code tends to
create quite a few template
instantiations. The C++ standard
library relies on this aggressive
optimization. Functors are only
performant if the overhead of
instantiating and destructing the
object can be optimized away.
operator[] on a vector is only comparable to raw
array indexing in performance
because the entire operator can be
inlined and thus removed entirely
from the compiled code. C# and Java
make a lot of guarantees about the
output of the compiler. If I define
a class in C#, then that class will
exist in the resulting assembly.
Even if I never use it. Even if all
calls to its member functions could
be inlined. The class has to be
there, so that reflection can find
it. Part of this is alleviated by C#
compiling to bytecode, which means
that the JIT compiler can remove
class definitions and inline
functions if it likes, even if the
initial C# compiler can't. In C++,
you only have one compiler, and it
has to output efficient code. If you
were allowed to inspect the metadata
of a C++ executable, you'd expect to
see every class it defined, which
means that the compiler would have
to preserve all the defined classes,
even if they're not necessary.

-
And then there are templates.
Templates in C++ are nothing like
generics in other languages. Every
template instantiation creates a
new type. std::vector is a completely separate class from
std::vector. That adds up to
a lot of different types in a entire
program. What should our reflection
see? The template std::vector? But
how can it, since that's a
source-code construct, which has no
meaning at runtime? It'd have to see
the separate classes
std::vector and
std::vector. And
std::vector::iterator and
std::vector::iterator, same
for const_iterator and so on. And
once you step into template
metaprogramming, you quickly end up
instantiating hundreds of templates,
all of which get inlined and removed
again by the compiler. They have no
meaning, except as part of a
compile-time metaprogram. Should all
these hundreds of classes be visible
to reflection? They'd have to,
because otherwise our reflection
would be useless, if it doesn't even guarantee that the classes I defined will actually be there. And a side problem is that the template class doesn't exist until it is instantiated. Imagine a program which uses std::vector. Should our reflection system be able to see std::vector::iterator? On one hand, you'd certainly expect so. It's an important class, and it's defined in terms of std::vector, which does exist in the metadata. On the other hand, if the program never actually uses this iterator class template, its type will never have been instantiated, and so the compiler won't have generated the class in the first place. And it's too late to create it at runtime, since it requires access to the source code.

  • And finally, reflection isn't quite


as vital in C++ as it is in C#. The
reason is again, template
metaprogramming. It can't solve
everything, but for many cases where
you'd otherwise resort to
reflection, it's possible to write a
metaprogram which does the same
thing at compile-time.
boost::type_traits is a simple
example. You want to know about type
T? Check its type_traits. In C#,
you'd have to fish around after its
type using reflection. Reflection
would still be useful for some
things (the main use I can see,
which metaprogramming can't easily
replace, is for autogenerated
serialization code), but it would
carry some significant costs for
C++, and it's just not necessary as often as it is in other languages.

Edit:
In response to comments:

cdleary:
Yes, debug symbols do something similar, in that they store metadata about

Context

Stack Overflow Q#359237, score: 675

Revisions (0)

No revisions yet.