Compile-time reflection
Kirk McDonald
kirklin.mcdonald at gmail.com
Sun Jul 1 17:17:59 PDT 2007
Christopher Wright wrote:
> Kirk McDonald wrote:
> <snip>
>
>> The first thing a compile-time reflection mechanism needs is a way to,
>> given a symbol, derive a tuple of the signatures of the function
>> overloads. There is no immediately obvious syntax for this.
>
>
> Overloads are entirely separate functions. If you go through
> ClassInfo.vtbl, that gives you each overload separately. And the only
> thing overloads have in common are their names. So is this actually
> important?
>
I am interested in compile-time reflection. The vtable doesn't exist at
compile-time. The only way to refer to a function at compile-time is
through a combination of the symbol name and the signature.
Anything involving function pointers is necessarily a runtime operation.
[snip]
> <snip>
>
>> foo.tupleof => Tuple!(void function(), void function(int), void
>> function(int, int, int))
>
>
> Okay, sounds simple enough, but why do you need each overload? They're
> separate functions; they don't have anything in common, strictly
> speaking, except the name.
>
Same reason: It is a strictly compile-time operation.
>> It should be clear, then, that automatically deriving the overloads of
>> a given function is very important. Another piece of information that
>> is useful is whether a given function has default arguments, and how
>> many. The tupleof() syntax can be re-used for this:
>>
>> tupleof(foo, void function(int, int, int)) => Tuple!(void
>> function(int, int))
>
>
> This is interesting. Currently, there's no way to get which arguments
> are omissible.
>
Not entirely true; see std.bind.minNumArgs (which is a variadic version,
by h3r3tic, of a non-variadic template I wrote before we had tuples). I
am simply proposing making this a language feature, rather than the hack
it currently is.
> ...
>
>> D does not really have pointers to member functions. It is possible to
>> fake them with some delegate trickery. In particular, there is no way
>> to directly call an alias of a member function. This is important, as
>> I will get to later.
>
>
> The reason for this is obvious; the compiler rewrites the functions as
> you describe below. I haven't looked, but I'd guess a delegate is
> something like this:
> struct delegate (T, R, U...) {
> void* func;
> T obj;
> R opCall(U u) { return *func(obj, u); }
> }
>
> ...
>
The ABI is different; the instance is passed in a register, or somesuch.
>> A.methodsof => Tuple!(A.bar, A.baz, A.foobar, A.foobaz)
>> B.methodsof => Tuple!(A.bar, A.foobar, A.foobaz, B.foo, B.baz)
>
>
> You can already get this through A.classinfo.vtbl. That contains all
> functions that are valid for the class. You can create a template that
> will determine which functions are inherited, though you cannot say
> which override functions from the base class with any certainty.
>
Again, the vtable is not compile-time information.
>> static(A.bar == static) == false
>> static(A.bar == final) == false
>> static(A.bar == virtual) == true
>
>
> Currently, there's no way I know of to get this information. The
> is(typeof()) system works with all functions, static or not, whether you
> use them from a type or from an instance.
>
> Hack? Do everything from instance variables. Dunno what to do about
> final, though.
>
> Checking about final stuff matters if you want your program to behave
> differently toward final methods, but nothing in ClassInfo prevents you
> from replacing a final method.
My interest is in improving Pyd. Given a class, I want to generate a
Python type wrapping the entirety of that class, as well as a D subclass
of the type, providing virtual dispatching to the Python type. This
means I effectively have to know /everything/ about the class and its
methods, at compile-time.
--
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org
More information about the Digitalmars-d
mailing list