Bash++ v0.7: RTTI and Runtime-Inferred Dynamic Cast Targets
Bash++ v0.7 introduces some expanded usage of RTTI (Run-Time Type Information) in the language. For some time, type information about objects has been stored at runtime (this is necessary, for example, for virtual methods) but mostly inaccessible to the programmer. From the programmer’s perspective, the only direct window into this information has been the @dynamic_cast operator:
@Object* obj=@dynamic_cast<Object> &@other_obj
And we could then compare @obj to @nullptr to see if the cast was successful. This tells you whether @other_obj’s type is either Object or some derived type along the inheritance chain. This is useful, but limited.
@typeof
Bash++ v0.7 introduces the @typeof operator, which allows you to query the exact type of an object at runtime:
The @typeof operator expects a pointer to an object, and its output is the name of the class as a string. This allows you to perform exact type comparisons, which can be useful in certain scenarios.
Runtime-Inferred Dynamic Cast Targets
This change, to me, is more interesting.
Up until v0.7, the @dynamic_cast operator has only accepted a class name as its target type. This meant that the target type had to be known at compile time.
With v0.7, the @dynamic_cast operator can now accept a shell variable or object reference which is expected to contain a class name at runtime:
cast_to_class="MyClass"
In these cases, the compiler simply accepts the reality that it cannot verify the correctness of the target type at compile time.
Previously, if an invalid class name was given to @dynamic_cast, the compiler would emit an error and halt compilation. This behavior has been changed – the compiler will now emit a warning instead. In the case of a runtime-inferred target type, the compiler cannot verify the correctness of the target type, so it will not emit any warning.
This opens up a lot of new possibilities for us. Immediately with this change, we’re able to introduce Typed containers to the standard library (TypedArray, TypedStack, TypedQueue, etc, as well as Typed versions of all the Shared containers for multi-process concurrency).
The Typed containers work essentially like this:
@class TypedStack : Stack
These typed containers use runtime-inferred cast targets to enforce type constraints on the elements they contain. In other words, they will refuse to accept any primitives which are not pointers to objects of the correct type.
If you’re, for example, using a TypedStack of @Object, then it’s completely safe to do something like this:
@Object* top=@stack.top
And use @top as an @Object* without any further casting or verification, because the TypedStack has already guaranteed that everything it contains is an @Object* or derived type.