On type functions
Steven Schveighoffer
schveiguy at gmail.com
Sun May 3 15:12:32 UTC 2020
On 5/3/20 5:35 AM, Stefan Koch wrote:
> First things first, discussions about syntax are NOT WELCOME in this topic!
> Type functions are something which I have had floating around my mind
> since early 2018.
> While working on newCTFE I did performance measurements on code which
> people send me and which they believed was slow because of CTFE.
> It turned out that actually recursive introspection templates and
> "unrolled tuple foreach" where actually at faut, most of the time.
> Because they littered the code with many many statements and symbols
> that were only temporarily needed at compile time. And yet were
> incorporated into the generated code.
>
> I told people to stay away from templates if they somehow could.
> However they could not since introspection capabilities
> (__traits(allMembers) and such) only work if you can work with types.
> Since templates are the only construct in the language which can take
> type parameters.
> You're stuck with them and the associated overhead.
>
> The template overhead:
> - needs to create persistent immutable types to maintain language
> invariants such as (is(T!void == T!void))
> - inherently constraint to strongly pure functional style and
> therefore locked into recursive patterns. (which are inherently slow (!)
> (Even if some language manage to optimize based on the stronger
> guarantees, that optimization itself takes time (which we don't have at
> compile time)))
> - because of the recursive style they are hard to understand once
> they are meant to change behavior based on different types.
>
> About a year ago it struck me that nobody actually _wanted_ to use
> templates, for introspection.
> Using templates for metaprogramming is like using a screwdriver to
> hammer nails into a wall.
> If you had a hammer you'd use it, but if you don't the screwdriver is
> still a better option than doing it with your bear hands.
> templates were invented to provide type parameterization not to express
> computation.
>
> Let's take something that was designed to express computation,
> functions, and extend it with the ability to take types as objects.
> The type function is born. (I thought I came up with it, but recently
> remembered that I first saw it in idris (https://www.idris-lang.org/))
>
> D already have a way of expressing a "type variable" the `alias` keyword.
> so having a function such as
>
> bool isInt(alias T)
> {
> return is(T == int);
> }
>
> as a completely natural thing to write.
>
> let's now say we wanted to code to serialize a struct to a human
> readable string.
> Avoiding templates unnecessary templates. (i.e.) the maximum number of
> template-instances creating during this task should be LINEAR to the
> number of structs printed.
>
> string NameOfField(alias T, size_t fIdx)
> {
> assert(is(typeof(T.tupleof), T.stringof ~ " has no .tupleof
> property maybe it's not an aggregate?");
> return __traits(identifier, T.tupleof[fIdx]);
> }
>
>
> string structToString(T)(T struct_)
> {
>
> char[] result;
> result ~= __traits(identifier, T) ~ " :: {\n";
> foreach(fIdx, field; struct_.tupleof)
> {
> result ~= NameOfField!(T, fIdx) ~ " : "; // looks like a
> templates but it's not!
>
> }
> }
This is cool, but we can already do this (as Adam says). Would it not be
more prudent for this to just be a UDA that says "don't put in symbol
table"?
What I want is symbol manipulation like variables.
i.e.:
alias types = AliasSeq!(int, char, bool);
alias[] ctSort(alias[] items) { return sort!(t => t.name)(types); } //
or something like this
static assert(is(ctSort(types) == AliasSeq!(bool, char, int)));
I can already do this too, but painfully.
-Steve
More information about the Digitalmars-d
mailing list