I'm looking for two things- speed, and integration. Usually the two go together, and with familiarity. Unfortunately, for C++, there are pretty much no languages that offer speed and integration. I've used Lua and it sucked, horrifically. I spent the whole time writing bindings and nowhere near enough time actually writing code.
Language features? The point of embedding a scripting language is not so that it can have whizzy dynamic language features that my original language didn't have, it's so that it can be interpreted at run-time. I really don't care beyond that, as long as it's basically functional, then that's fine- and fits with my host language (in this case C++). However, amazingly, languages that are designed to be integrated into host applications utterly fail the the part about integration.
Do I need co-routines? No, I do not need co-routines. Do I need dynamic typing? No, I need to know what types are coming back at me from my scripting language, and since all of my existing code is built around very strong typing, I'd really like my script code to be able to respect that too. Do I need garbage collection? No, my types already manage their own resources, and I definitely do want deterministic destruction. Do I want goto? No- I want to throw exceptions.
The trouble I found was that basically all the existing scripting languages were designed to extend C, not C++, and don't properly support the C++ model in many ways, and in addition to this, they have totally different semantics. How on earth am I going to translate
shared_ptr, which is automatic deterministic destruction, into a garbage-collected environment? You can write whatever wrapping libraries you want, you won't change the underlying language semantics being incompatible with the language you're trying to extend with it. How can I ensure that this
void* is the right type? How can I deal with inheritance? How do I throw and catch exceptions? It just doesn't work.
A good scripting language for C++ would be statically typed, value semantics, deterministically destructed, throw and catch exceptions and respect my destructors/constructors/copy constructors, because then all my types will just work, nice and easy, and the resulting language will be fast and support all my original semantics, easy to bind to.