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