First life-signs of type functions

Johannes Loher johannes.loher at fg4f.de
Tue May 12 11:39:04 UTC 2020


On Tuesday, 12 May 2020 at 06:42:02 UTC, Stefan Koch wrote:
> On Tuesday, 12 May 2020 at 01:44:45 UTC, Steven Schveighoffer 
> wrote:
>> On 5/11/20 5:58 PM, Stefan Koch wrote:
>>> 
>>> In a type function alias cannot bind to values at all.
>>> It can only bind to symbols or types.
>>
>> This seems like a problematic limitation. Aliases can bind to 
>> values when they are part of a tuple. This means that type 
>> functions are going to have to do weird template acrobatics to 
>> deal with mixed tuples.
>>
>> For a long time, alias parameters wouldn't bind to int because 
>> it was a keyword, not a symbol, even though you could alias 
>> int as a declaration. It wouldn't even bind them to aliases of 
>> int (even though they are not keywords). That has since been 
>> fixed, and everything works great. I think we should avoid 
>> arbitrary limitations like this, even if it's harder to get it 
>> to work.
>>
>> -Steve
>
> The reason that happened is not so much a parser issue.
> But it's because Basic Types are not Symbols.
> Which is indeed a more or less arbitrary limitation.
>
> Let's go through the reasoning for type functions now.
> let's assume alias A would bind to a value, the string foo
> for example.
>
> string F(alias A)
> {
>     pragma(msg, typeof(A).stringof); // prints alias
>     pragma(__traits(identifier, A); // error a string has no 
> identifer.
>     pragma(msg, is(A == string)); // prints false, because A 
> does not hold the type string
>     pragma(msg, A) prints "foo";
>     pragma(msg, A == "foo") // error can't compare alias and 
> string
>     pragma(msg, is(A, "foo") // doesn't parse. The string "foo" 
> is not a valid identifier
>     return A; // error alias does not implicitly convert to 
> string.
> }
>
> You see there would not be a point in allowing that.

Honestly, to me this sounds like a total mess. If templates allow 
binding alias to a value, so should type functions, or they 
should use a different name than "alias". Otherwise it's just 
confusing. To me it looks like for type functions, you think of 
"alias" as something like the "type of types". But for alias 
template parameters and alias declarations it is something 
completely different (as Steven  explained, it is an unrestricted 
compile-time name). For example, consider the following:


enum tpl(alias i) = i == "foo";

void main()
{
     static immutable a = "foo";
     enum b = "foo";
     auto c = "foo";
     static assert(tpl!"foo" == true);
     static assert(tpl!a == true);
     static assert(tpl!b == true);
     static assert(!__traits(compiles, tpl!c));
}

If type functions also use "alias" to specify their parameters, 
from a user perspective, I'd expect the following to work just as 
well:

auto tpl(alias i)
{
    return i == "foo";
}

void main()
{
     static immutable a = "foo";
     enum b = "foo";
     auto c = "foo";
     static assert(tpl("foo") == true);
     static assert(tpl(a) == true);
     static assert(tpl(b) == true);
     static assert(!__traits(compiles, tpl(c)));
}

I agree that maybe there is not that much for it (you do intend 
to allow mixing with "regular" parameters, right? So these could 
be used most of the time to solve this). But if "alias" is used 
and this does not work, it just breaks expectations. What about 
simply using "type" (or something similar) instead? You are 
calling it _type_ functions after all...


I believe most of these issues misunderstandings come from the 
fact that people seem to look at this from different angles. From 
what I understand, you mostly look at it from an implementation 
perspective (and I am very grateful to you for taking the 
initiative here) but most others will look at it from a 
theoretical / language design perspective.

For example, you mentioned somewhere that you believe this could 
be part of the language much sooner than new CTFE. Personally, I 
couldn't agree less: The implementation as you envision it now 
might be done much faster than finishing new CTFE but for CTFE, 
we already know all the interactions with with other language 
features and how it should behave. For type functions, we 
basically have no clue. A _lot_ of thought needs to go into that 
before we can actually get something like this in the language in 
order to ensure we still have a consistent language and its 
features interact well. A "naive" implementation just won't do it.

That said, I don't want to diminish your efforts here at all. On 
the contrary, I appreciate it very much. This is a very good way 
to actually learn about possible interactions and how this fits 
in the language.




More information about the Digitalmars-d mailing list