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