October 08, 2020
On Thursday, 8 October 2020 at 11:47:48 UTC, Stefan Koch wrote:

>>
>> filter!(__traits(isPOD), A, B C); // no way
>> filter!(isPod, A, B, C); // can be
>
> or you use type functions which can use them at ctfe;)

You'd still have to wrap __traits in a type function to pass it to another function?





October 08, 2020
On Thursday, 8 October 2020 at 12:54:49 UTC, Adam D. Ruppe wrote:

>
> I kinda wish we had a template lambda.

Would be cool.
October 08, 2020
On 10/8/20 4:12 AM, Kagamin wrote:
> On Wednesday, 7 October 2020 at 18:46:07 UTC, Steven Schveighoffer wrote:
>> Why both? The first thing that struck me is that, std.stdio is NOT a type. `is` specifically says it works with types. So that seems out of place (indeed the documentation does not mention anything special about this).
> 
> Guess, it's a bit of pl theory, I saw mentioned somewhere that modules count as types. Not sure about packages though.

It's literally special cased in the code:

https://github.com/dlang/dmd/blob/013eccaf113e6f23784c615d3ec66434c3629197/src/dmd/expressionsem.d#L5418

-Steve
October 08, 2020
On Thu, Oct 08, 2020 at 12:54:49PM +0000, Adam D. Ruppe via Digitalmars-d wrote:
> On Thursday, 8 October 2020 at 10:11:59 UTC, Max Samukha wrote:
> > Wrapping __traits in templates is a necessity if you want to use them for anything interesting (such as passing them to higher order functions):
> 
> I kinda wish we had a template lambda.

Me too!!!  I've been avoiding to use Filter, et al, because I'm forced to declare a bunch of helper templates just for trivial predicates. If lambda syntax could be extended to templates, that would make it much nicer to use.


T

-- 
Fact is stranger than fiction.
October 08, 2020
On 10/8/20 10:08 AM, H. S. Teoh wrote:
> On Thu, Oct 08, 2020 at 12:54:49PM +0000, Adam D. Ruppe via Digitalmars-d wrote:
>> On Thursday, 8 October 2020 at 10:11:59 UTC, Max Samukha wrote:
>>> Wrapping __traits in templates is a necessity if you want to use
>>> them for anything interesting (such as passing them to higher order
>>> functions):
>>
>> I kinda wish we had a template lambda.
> 
> Me too!!!  I've been avoiding to use Filter, et al, because I'm forced
> to declare a bunch of helper templates just for trivial predicates. If
> lambda syntax could be extended to templates, that would make it much
> nicer to use.

We recently had the AliasSeq pattern recognized by the compiler and it no longer stores a template for it.

can we do the same thing for __traits? In other words, it can recognize the pattern:

template foo(...)
{
   alias foo = __traits(...);
}

And avoid setting up templates for this.

I think the AliasSeq pattern still runs through the template machinery, which is not a good thing. But perhaps this can be addressed orthogonally.

-Steve
October 08, 2020
On Thursday, 8 October 2020 at 09:38:40 UTC, Jacob Carlborg wrote:
> On Wednesday, 7 October 2020 at 19:15:30 UTC, Paul Backus wrote:
>
>> Here's my strawman proposal: turn all __traits into properties. A few before-and-after examples:
>>
>> __traits(isModule, foo)
>>   => foo.__isModule
>>
>> __traits(getMember, T, "x")
>>   => T.__member("x")
>>
>> __traits(compiles, some(kind, of + expression))
>>   => (some(kind, of + expression)).__compiles
>
> Oh, god, no. We already have way too many special magic members. We don't need any more. `__traits` is great because it has it's own namespace. It occupies just one keyword and you can add all the identifiers in the world without the risk of breaking existing code.
>
> Yes, I know that identifiers starting with `__` is reserved, but there's nothing that stops anyone from using an identifier which starts with `__`.

Except, you know, the language spec. I understand the desire to avoid breaking changes if possible, but why even bother to have reserved identifiers in the first place if you're going to treat them as sarcosanct? Even the ISO C standard is willing to make changes like this, and that's about the most conservative language there is.

In any case, it would be quite easy to put this behind a `-preview` flag and have a deprecation period during which the compiler warns about all uses of the identifiers that the language is planning to claim.

> In my opinion is the double underscores that makes it look ugly. Your suggestion is not an improvement. Same thing with UFCS, it's no point if you need to use parentheses anyway: `(1 + 2).toString`.

Are you sure? You really can't see any difference in readability between this

    __traits(getOverloads, __traits(parent, sym), __traits(identifier, sym))

and this?

   sym.__parent.__overloads(sym.__identifier)

Maybe it's not perfect, but surely it's still an improvement.

> If we need a new syntax for this (which I don't think we need), it would be better with some built-in/compiler recognized functions declared somewhere in the `core` package. Then it would be possible to use standard language constructs to deal with multiple symbols with the same name.

I would also be fine with this. Of course, they would have to be "magic" functions specially recognized by the compiler, not real ones, but at least that would let us get rid of the dreaded double-underscore.
October 08, 2020
On 10/7/20 4:19 PM, Paul Backus wrote:
> On Wednesday, 7 October 2020 at 20:08:02 UTC, Stefan Koch wrote:
>> On Wednesday, 7 October 2020 at 19:15:30 UTC, Paul Backus wrote:
>>>
>>> Here's my strawman proposal: turn all __traits into properties. A few before-and-after examples:
>>>
>>> __traits(isModule, foo)
>>>   => foo.__isModule
>>>
>>> __traits(getMember, T, "x")
>>>   => T.__member("x")
>>>
>>> __traits(compiles, some(kind, of + expression))
>>>   => (some(kind, of + expression)).__compiles
>>
>> I don't think that looks much better.
>> __traits are actually fine in my eyes.
>> It's easy on semantic and parser.
>> Determining whether a trait applies and therefore should be imported into the properties of a given node is more nasty.
>> (It means you have to change semanticX and semanticY as well as resolvePropertiesX in DMD)
> 
> Couldn't you unconditionally lower <Node>.__isModule to __traits(isModule, <Node>) regardless of what type of node it is, and rely on the existing error messages for incorrect trait arguments? You don't have to worry about shadowing "real" properties, because anything that starts with "__" is a reserved identifier.

If we got type functions, and have UFCS, isn't this as easy as e.g.:

bool isModule(alias x) { return __traits(isModule, x); }

static assert(std.stdio.isModule);

bool hasMember(alias T, string membername) { return __traits(hasMember, T, membername); }

static assert(T.hasMember("foo"));

alias getMember(alias T, string membername) { return __traits(getMember, T, membername));

static assert(is(typeof(T.getMember("foo")) == int);

alias foomember = someTInstance.getMember("foo");

Then we don't have to care about keywords, or adding properties that can't be overridden, etc. It's just a normal symbol we can define wherever (like std.traits).

-Steve
October 08, 2020
On Thursday, 8 October 2020 at 16:49:50 UTC, Steven Schveighoffer wrote:
>
> If we got type functions, and have UFCS, isn't this as easy as e.g.:
>
> bool isModule(alias x) { return __traits(isModule, x); }
>
> static assert(std.stdio.isModule);

Ok, now do __traits(getMember, variable, "foo") and __traits(compiles, expression). :)

Using type functions to wrap __traits has the same issues as using templates to wrap __traits. In the common case, it works, but in the general case, it fails, because __traits have special privileges that no other construct in the D language (including templates, functions, and type functions) can fully imitate.
October 08, 2020
On 10/8/20 1:43 PM, Paul Backus wrote:
> On Thursday, 8 October 2020 at 16:49:50 UTC, Steven Schveighoffer wrote:
>>
>> If we got type functions, and have UFCS, isn't this as easy as e.g.:
>>
>> bool isModule(alias x) { return __traits(isModule, x); }
>>
>> static assert(std.stdio.isModule);
> 
> Ok, now do __traits(getMember, variable, "foo") and __traits(compiles, expression). :)

I did getMember already.

And it can't do __traits(compiles). So, just use __traits(compiles) for that one.

> Using type functions to wrap __traits has the same issues as using templates to wrap __traits. In the common case, it works, but in the general case, it fails, because __traits have special privileges that no other construct in the D language (including templates, functions, and type functions) can fully imitate.

I'm not sure that's 100% true for type functions -- they aren't in there yet.

-Steve
October 08, 2020
On Thursday, 8 October 2020 at 17:55:21 UTC, Steven Schveighoffer wrote:
>
> I did getMember already.

You did getMember for a type, not a variable. getMember for a type evaluates to a symbol, but getMember for a variable evaluates to an expression.

> I'm not sure that's 100% true for type functions -- they aren't in there yet.

In order to do everything that __traits can do, type functions would have to be polymorphic, which is contrary to their design goals.