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