views:

389

answers:

3

LLVM has it's own hand rolled alternative to RTTI that is a speed improvement over built-in RTTI and allows dynamic casting to classes with no vtable (dyn_cast). However, it can still be used in exactly the way that dynamic_cast<> is used though it does allow it to be used with more classes.

dyn_cast<> template documentation

LLVM is a reputable C++ project so this seems to fly in the face of the common saying that too many dynamic casts is a sign of bad design, also known as a code smell. Surely a better performing dynamic cast does nothing to improve its use in design than a standard dynamic_cast. So who is right here? Are there cases where large-scale use of dynamic casting is a good design choice in C++ code? Google turns up 690 occurrences of this kind of dynamic casting in the LLVM trunk source code.

Uses of dyn_cast<> in LLVM trunk

+1  A: 

I think dynamics casts are bad not because they are slow, but because they imply that your code is too tightly coupled.

dicroce
They are very slow too, though. About 1 microsec a pop for us.
Crashworks
@Crashworks - How deep is the inheritance hierarchy? I believe GCC's implementation of `dynamic_cast` is O(n) in the depth, which can be very bad for some systems.
Tom
I think it's about 6-8 levels in the case I tested. There's literally thousands of classes throughout the entire app.
Crashworks
I agree so are you implying that LLVM is too tightly coupled and thus not a good design?
Khaki
A: 

I've only taken a very quick look at the implementation of dyn_cast and isa in the LLVM documentation.

The exmaple in the code has the following:

struct bar {
  bar() {}
private:
  bar(const bar &);

};
struct foo {
  void ext() const;
  /*  static bool classof(const bar *X) {
    cerr << "Classof: " << X << "\n";
    return true;
    }*/
};

template <> inline bool isa_impl<foo,bar>(const bar &Val) {
  errs() << "Classof: " << &Val << "\n";
  return true;
}

The test is called with a B and has:

if (!isa<foo>(B1)) return;
if (!isa<foo>(B2)) return;

If I understand what's going on correctly, the isa template (which is used by dyn_cast) uses the explicit specialization of isa_impl to link bar with foo. In the examples given it seems that isa<foo>(B1) returns true!

Anyway, this is very different behaviour to that of dynamic_cast, so I really don't think you can compare them against each other.

Obviously, I may be mis-understanding what LLVM is doing, so please let me know if I've not understood the code!

Richard Corden
Directly from the documentation:The dyn_cast<> operator is a "checking cast" operation. It checks to see if the operand is of the specified type, and if so, returns a pointer to it (this operator does not work with references). If the operand is not of the correct type, a null pointer is returned. Thus, this works very much like the dynamic_cast<> operator in C++, and should be used in the same circumstances.So I don't see why you can't compare dynamic_cast against dyn_cast. In your example I don't see where B1 and B2 come from.
Khaki
The above code comes from a link off the page referred to in the question. This is their (ie. LLVM's) code. Here's the direct link: http://llvm.org/doxygen/Casting_8h-source.html. B1 and B2 come from an example on that page lower down. I have just cut and pasted the code from their header. BTW, nothing that you've pasted here actually says how the dynamic cast takes place. It just says its a "checking cast" similar to dynamic_cast.
Richard Corden
I don't think the implementation really affects the question I'm asking here. The key quote from the documentation verbatim is this 'Thus, this works very much like the dynamic_cast<> operator in C++, and should be used in the same circumstances.'
Khaki
The implementation is pretty important to your question. Your question specifically asks if its OK to use the LLVM version of dynamic_cast because it doesn't have the overhead of dynamic_Cast. My answer is that from my reading of the code what LLVM provides has slightly different functionality to dynamic_cast. I don't know the library enough to be able to tell you exactly what the differences are - but you would need to make yourself aware of those differences before you do a replace-all!
Richard Corden
+3  A: 

While performance hits are a reason to avoid dynamic_cast<> for large class hierarchies, it's not the only reason you might want to avoid them. Better performing or not, one should not be more encouraged to use dyn_cast<> because of this claim.

On the other hand, there's absolutely nothing wrong with using dynamic_cast<> when it's the best tool for the job. If its use is justified, and the cleanest way to solve a problem, then it's always right, regardless of the "common saying".

I would certainly not steer clear of popular projects simply because they use dynamic_cast<>s, gotos or any other idiom that's fallen out of favour.

Matt Joiner
Absolutely, I think it's a great project so does that mean we should take less serious notice of advice to steer clear of `dynamic_cast<>`?
Khaki
no, you should keep the advice in mind when you're using them and think, "is this the best way to do this?"
Matt Joiner