Reimplementing the bulk of std.meta iteratively

Andrei Alexandrescu SeeWebsiteForEmail at erdani.com
Thu Oct 1 15:21:40 UTC 2020


On 10/1/20 2:51 AM, Stefan Koch wrote:
> On Thursday, 1 October 2020 at 04:08:26 UTC, Walter Bright wrote:
>> On 9/28/2020 3:46 PM, Bruce Carneal wrote:
>>> Finally, I'd love to hear your comments on type functions vs 
>>> reify/dereify.  It's certainly possible that I've missed something.  
>>> Maybe it's a type functions+ solution we should be seeking (type 
>>> functions for everything they can do, and some LDM for anything 
>>> beyond their capability).
>>
>> Andrei and I have been mulling over what to do for a while, and have 
>> gone through several ideas.
>>
>> What we're looking for is not a top level solution. We want a 
>> fundamental building block, upon which the rest of D's features can 
>> exploit naturally and productively. Something that can be explained in 
>> 30 seconds.
> 
> Type functions take less than 30 seconds.
> They take zero seconds.
> 
> Do you remember Andrei's non working example?
> 
>> alias MostDerived(Args...) = dereify!({
>>     auto ids = reify!Args;
>>     sort!((a, b) => is(dereify!a : dereify!b))(ids);
>>     return ids;
>> }());
> 
> Here is the correct type function which actually works!
> 
> alias[] MostDerived(alias[] types ...)
> {
>      sort!((alias a, alias b) => is(a : b))(types);
>      return types;
> }
> 
> It is Andrei thought would work.
> With type functions it just works.

 From https://gist.github.com/andralex/0d85df38be2d9ffbe89cf1fb51c44213:

alias DerivedToFront(Args...) = dereify!({
     auto ids = reifyArray!Args;
     ids.sort;
     return ids;
}());

That code defines opCmp such that a < b iff a is a subtype of b, a nice 
touch reminiscent of the <: operator used in type theory. To implement 
that, the reified type stores the bases (conversion targets) of the type 
at construction time. This is easy to generalize to numeric and array 
types, and some more work to get going for things like covariant functions.

One litmus test is to redo Variant "the right way" (btw it should be 
called Any and moved to druntime). Currently Variant reifies the type 
into a pointer to function, and uses that pointer to function to 
dispatch type-dependent work. It is quite messy and incorrect in places. 
"The right way" would be for the reified type to have enough information 
to allow things like testing for subtyping/convertibility. Currently 
Variant is essentially incomplete and incorrect (see 
https://github.com/dlang/phobos/blob/master/std/variant.d#L285) because 
it builds on the shaky ground of 
https://github.com/dlang/phobos/blob/master/std/traits.d#L5027, a sort 
of a best-effort approach to figuring out the definition of implicit 
conversions scattered across the language definition (if documented in 
entirety at all). Having a clear definition of what implicitly converts 
to what would be a nice perk.

One interesting thing about Variant's primitives is that information is 
half-and-half: one half is present at compile-time, i.e. "Can I read a 
value of type T?" and the other half is present at runtime, in the 
reified format stored in the Variant. Given that the latter is dynamic, 
there's no way around reifying T as well and then using the reified 
types for testing.


More information about the Digitalmars-d mailing list