__typeid
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Sat Aug 1 16:12:58 UTC 2020
Progress is moving along nicely with __typeid. Currently all types aside
from `struct`s, `class`es and `interface`s are supported:
https://github.com/dlang/druntime/pull/3174
I don't see major issues ahead, so __typeid!(T) should supplant the
functionality provided by typeid(T) with no or little magic needed on
the compiler side. It would allow deleting a gnarly part of the compiler
- so convoluted, in fact, that Walter himself gave up on modularizing it
and decided to wait for __typeid to be finished so he throws all that
away in one fell swoop. That's going to be fun.
Reading a bit more about TypeInfo and related stuff, I figure (and
correct me if I'm wrong) that the entire machinery is currently used for
the following purposes (only):
* Built-in associative arrays (which ought to be phased out)
* Inform the GC of what it needs to scan (provided in an awkward manner
though, this is subject to a later discussion)
* Dynamic cast information for class objects
* Object creation for Object.factory() (which also should be phased out)
The API provided by TypeInfo has evolved with these uses in mind, so the
bulk of it is concerned with primitives for associative arrays such as
comparison, hashing, and swapping.
The more exciting part is not just replacing the existing functionality,
but taking it forward. In the future:
* Built-in associative arrays should be templated and make no use of
typeid at all
* The GC interface should be done through functions, not data
structures. __typeid!(T) would provide a function scan(T*) that scans
the given object and all pointers it embeds, transitively. That is easy
to implement in an efficient manner because the static information about
T (and therefore its .tupleof) is available when the function is
generated. Templates, wheee!
* Dynamic cast information for class objects should be kept, perhaps
made more efficiently than a linear search.
* Object creation primitives should be only provided in an opt-in
manner. If a class hierarchy wants to expose a factory function, all it
needs to do is inherit a tag interface:
interface DynamicallyConstructible {}
During the generation of __typeid, the inheritance of this tag is
detected and the appropriate construction code is generated.
* An important use of __typeid will be to implement Variant "the right
way". Using the __typeid instead of the unsightly pointer to handler
function in Variant would go a long way toward simplifying it. the
__typeid API would be therefore geared toward the needs of that type.
I've come to the realization that that type is essential for the use of
D in dynamic contexts. I'd name that type Box, put it in druntime, and
make it available to Das Besser C.
* Once Box is present, much more is possible. It's not difficult to do
introspection during compilation on a class object and expose its
methods at runtime. We'd do that only if another tag interface is
inherited, again in an opt-in manner:
interface DynamicallyInvokable {}
So it becomes possible to expose objects at runtime, making uses like
this possible:
// Inside the library
class Widget : DynamicallyInvokable
{
int frobnicate(double a, int b) { ... }
}
// Application that does NOT import the widget module
// Load the typeid(Widget) from a dynamic library
TypeInfo ti = loadType("./mylibrary.so", "widget.Widget");
// Make a widget. Note that we do NOT have the Widget class definition!
Object w = ti.make();
// Call Widget.frobnicate an get its result
Box result = ti.invoke(w, "frobnicate", 3.14, 42);
// The Box contains an int
int x = result.get!int;
All of this is well within reach, but it's a fair amount of work.
More information about the Digitalmars-d
mailing list