October 05, 2020
On Monday, 5 October 2020 at 11:44:34 UTC, Stefan Koch wrote:
[...]

> I leave it up to you to decide which version is more understandable and extendable (should we ever get another basic type :))

cent and ucent are waiting ;-)

>
> As noted previously please do discuss!
> Maybe you like the template version more?
> Let me know.


October 05, 2020
On Monday, 5 October 2020 at 15:07:37 UTC, Patrick Schluter wrote:
> On Monday, 5 October 2020 at 11:44:34 UTC, Stefan Koch wrote:
> [...]
>
>> I leave it up to you to decide which version is more understandable and extendable (should we ever get another basic type :))
>
> cent and ucent are waiting ;-)
>
ooops, should have read the rest of the thread before commenting...

October 05, 2020
On Monday, 5 October 2020 at 12:50:39 UTC, Andrei Alexandrescu wrote:

> The existing implementation is ancient (e.g. predates std.meta) and certainly deserves a redoing with Filter, which turns it into a 3-liner (untested):
>
> alias Integrals = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList, float, double, real, char, wchar, dchar);
> alias convertsTo(U) = is(T : U);
> alias ImplicitConversionTargets(T) = Filter!(convertsTo, Integrals);

This code does not work.
I don't even need to compile it to see that.

October 05, 2020
On Monday, 5 October 2020 at 20:57:04 UTC, Stefan Koch wrote:
> On Monday, 5 October 2020 at 12:50:39 UTC, Andrei Alexandrescu wrote:
>
>> The existing implementation is ancient (e.g. predates std.meta) and certainly deserves a redoing with Filter, which turns it into a 3-liner (untested):
>>
>> alias Integrals = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList, float, double, real, char, wchar, dchar);
>> alias convertsTo(U) = is(T : U);
>> alias ImplicitConversionTargets(T) = Filter!(convertsTo, Integrals);
>
> This code does not work.
> I don't even need to compile it to see that.

It has some simple mistakes, but the fundamental idea is sound. Here's a version that actually compiles:

import std.meta;

alias Numerics = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real, char, wchar, dchar);
enum convertsTo(T, U) = is(T : U);
alias ImplicitConversionTargets(T) = Filter!(ApplyLeft!(convertsTo, T), Numerics);

// prints: (int, uint, long, ulong, float, double, real, dchar)
pragma(msg, ImplicitConversionTargets!int);
// prints: (float, double, real)
pragma(msg, ImplicitConversionTargets!double);
October 05, 2020
On Monday, 5 October 2020 at 11:44:34 UTC, Stefan Koch wrote:
> I leave it up to you to decide which version is more understandable and extendable (should we ever get another basic type :))

Also trivially easy with mixins. Normally I don't suggest doing things this way but for basic types mixin is guaranteed to work.

```

enum basic_types = ["bool", "ubyte", "char", "byte", "ushort", "wchar", "short", "uint", "dchar", "int", "ulong", "long"];

// to not import stdlib
alias AliasSeq(T...) = T;
string join(string[] s, string j) {
        string a;
        foreach(i; s)
                a ~= i ~ j;
        return a;
}

template basicTypeConvTargets(T) {
   // again, I copy/pasted your code with very slight modifications
    string[] helper() {
            string[] targets;
            targets.length = basic_types.length;
            size_t n = 0;
            static foreach(t;basic_types)
            {
                if (is(T : mixin(t)))
                {
                    targets[n++] = t;
                }
            }
            return targets[0 .. n];
    }

    mixin("alias basicTypeConvTargets = AliasSeq!(" ~ helper().join(",") ~ ");");
}

pragma(msg, basicTypeConvTargets!ushort);
October 05, 2020
On Monday, 5 October 2020 at 21:13:09 UTC, Paul Backus wrote:
> On Monday, 5 October 2020 at 20:57:04 UTC, Stefan Koch wrote:
>> On Monday, 5 October 2020 at 12:50:39 UTC, Andrei Alexandrescu wrote:
>>
>>> [...]
>>
>> This code does not work.
>> I don't even need to compile it to see that.
>
> It has some simple mistakes, but the fundamental idea is sound. Here's a version that actually compiles:
>
> import std.meta;
>
> alias Numerics = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real, char, wchar, dchar);
> enum convertsTo(T, U) = is(T : U);
> alias ImplicitConversionTargets(T) = Filter!(ApplyLeft!(convertsTo, T), Numerics);
>
> // prints: (int, uint, long, ulong, float, double, real, dchar)
> pragma(msg, ImplicitConversionTargets!int);
> // prints: (float, double, real)
> pragma(msg, ImplicitConversionTargets!double);

Now post it with all transitive dependencies.
And we have a fair comparison.
October 05, 2020
On Monday, 5 October 2020 at 21:20:15 UTC, Adam D. Ruppe wrote:
> On Monday, 5 October 2020 at 11:44:34 UTC, Stefan Koch wrote:
>> I leave it up to you to decide which version is more understandable and extendable (should we ever get another basic type :))
>
> Also trivially easy with mixins. Normally I don't suggest doing things this way but for basic types mixin is guaranteed to work.
>
> ```
>
> enum basic_types = ["bool", "ubyte", "char", "byte", "ushort", "wchar", "short", "uint", "dchar", "int", "ulong", "long"];
>
> // to not import stdlib
> alias AliasSeq(T...) = T;
> string join(string[] s, string j) {
>         string a;
>         foreach(i; s)
>                 a ~= i ~ j;
>         return a;
> }
>
> template basicTypeConvTargets(T) {
>    // again, I copy/pasted your code with very slight modifications
>     string[] helper() {
>             string[] targets;
>             targets.length = basic_types.length;
>             size_t n = 0;
>             static foreach(t;basic_types)
>             {
>                 if (is(T : mixin(t)))
>                 {
>                     targets[n++] = t;
>                 }
>             }
>             return targets[0 .. n];
>     }
>
>     mixin("alias basicTypeConvTargets = AliasSeq!(" ~ helper().join(",") ~ ");");
> }
>
> pragma(msg, basicTypeConvTargets!ushort);

Thats still kinda hideous compared to the TF version. I mean you can grep the TF version at first glance, you literally barely have to think about it. Your mixin version takes some skipping back and forth between the code to work out what its doing.

There's that maxim that your code is read many times more that it is written, even by yourself never mind by other people. So a piece of code that takes 10 seconds to understand vs 30 seconds is a huge win. Faster for people to debug modify, and less likely they'll introduce new bugs.

I mean if somebody comes along a year or two down the line to modify the TF version and the Mixin version, its not hard to imagine which one are they more likely to screw up.

Which makes me wonder what is going on with the people steering D that this doesnt seem to have any importance anymore?
October 05, 2020
On Monday, 5 October 2020 at 11:44:34 UTC, Stefan Koch wrote:
> Hi,
>
> I've posted an incomplete version of a semantic translation of ImplictConvTargets from a template into a type function.
>
> After a few rather trivial fixes let me show you what the code looks like now.
>
> ---
> alias type = alias;
>
> // needed to avoid deeper changes ... in the future it may be unnecessary.
> auto makeAliasArray(type[] types ...)
> {
>     return types;
> }
>
> enum basic_types = makeAliasArray(bool, ubyte, char, byte, ushort, wchar, short, uint, dchar, int, ulong, long);
>
> type[] convTargets(type T)
> {
>     if (isBasicType(T))
>         return basicTypeConvTargets(T);
>     return null;
> }
>
> bool isBasicType(type T)
> {
>     foreach(t;basic_types)
>     {
>         if (is(T == t))
>             return true;
>     }
>     return false;
> }
>
> type[] basicTypeConvTargets(type T)
> {
>     type[] targets;
>     targets.length = basic_types.length;
>     assert(isBasicType(T), "You may not call this function when you don't have a basic type ... (given: " ~ T.stringof ~ ")");
>     size_t n = 0;
>     foreach(t;basic_types)
>     {
>         if (is(T : t))
>         {
>             targets[n++] = t;
>         }
>     }
>     return targets[0 .. n];
> }
> // 42 lines including whitespace and comments
>
> pragma(msg, convTargets(long)); // outputs [(ulong), (long)]

It would be very impressive if the following works:

type[] basicTypeConvTargets(type T)
{
    assert(isBasicType(T), "You may not call this function when you don't have a basic type ... (given: " ~ T.stringof ~ ")");
    return basic_types.filter!((alias U) => is(T: U)).array;
}

Yes, it instantiates a few templates, but it also demonstrates that working with type-values is as easy as working with regular values.
October 05, 2020
On Monday, 5 October 2020 at 22:53:31 UTC, Meta wrote:
>
> type[] basicTypeConvTargets(type T)
> {
>     assert(isBasicType(T), "You may not call this function when you don't have a basic type ... (given: " ~ T.stringof ~ ")");
>     return basic_types.filter!((alias U) => is(T: U)).array;
> }
>
> Yes, it instantiates a few templates, but it also demonstrates that working with type-values is as easy as working with regular values.

That should work actually.

as long as you include "alias type = alias;"
which gives you the type type.
And then you can write
basic_types.filter!((type U) => is(T: U)).array;

If that doesn't work, I am going to fix it shortly.
October 06, 2020
On Monday, 5 October 2020 at 21:20:36 UTC, Stefan Koch wrote:
> On Monday, 5 October 2020 at 21:13:09 UTC, Paul Backus wrote:
>> On Monday, 5 October 2020 at 20:57:04 UTC, Stefan Koch wrote:
>>> On Monday, 5 October 2020 at 12:50:39 UTC, Andrei Alexandrescu wrote:
>>>
>>>> [...]
>>>
>>> This code does not work.
>>> I don't even need to compile it to see that.
>>
>> It has some simple mistakes, but the fundamental idea is sound. Here's a version that actually compiles:
>>
>> import std.meta;
>>
>> alias Numerics = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real, char, wchar, dchar);
>> enum convertsTo(T, U) = is(T : U);
>> alias ImplicitConversionTargets(T) = Filter!(ApplyLeft!(convertsTo, T), Numerics);
>>
>> // prints: (int, uint, long, ulong, float, double, real, dchar)
>> pragma(msg, ImplicitConversionTargets!int);
>> // prints: (float, double, real)
>> pragma(msg, ImplicitConversionTargets!double);
>
> Now post it with all transitive dependencies.
> And we have a fair comparison.

Post your code with all changes to the language and compiler. Then we have a fair comparison.