Thread overview
Type functions with std.algorithm
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Timon Gehr
Oct 12, 2020
Stefan Koch
October 11, 2020
The code below here works with the current talias_master branch!

alias type = __type;

type[] makeTypeArray(type[] types ...)
{
    return types;
}

import std.algorithm;

enum type[] types = makeTypeArray(int, uint, long, ulong);
enum size4 = types.filter!((type a) { return a.sizeof == 4; } );
pragma(msg, () {
    type[] result = [];
    foreach(t;size4)
    {
        result ~= t;
    }
    return result;
}().tupleof);
// outputs: tuple((int), (uint))
October 11, 2020
On Sunday, 11 October 2020 at 00:46:37 UTC, Stefan Koch wrote:
> The code below here works with the current talias_master branch!
>
> alias type = __type;
>
> type[] makeTypeArray(type[] types ...)
> {
>     return types;
> }
>
> import std.algorithm;
>
> enum type[] types = makeTypeArray(int, uint, long, ulong);
> enum size4 = types.filter!((type a) { return a.sizeof == 4; } );
> pragma(msg, () {
>     type[] result = [];
>     foreach(t;size4)
>     {
>         result ~= t;
>     }
>     return result;
> }().tupleof);
> // outputs: tuple((int), (uint))

Nice!

Is there an issue with `std.array.array`, or you just prefer manually converting the range to an array? Btw, dmd can evaluate ranges at compile-time (e.g. in static foreach), so .tupleof could potentially also do that (convert both ranges and arrays of types to a tuples).
October 11, 2020
On Sunday, 11 October 2020 at 06:22:26 UTC, Petar Kirov [ZombineDev] wrote:
> On Sunday, 11 October 2020 at 00:46:37 UTC, Stefan Koch wrote:
>> The code below here works with the current talias_master branch!
>>
>> alias type = __type;
>>
>> type[] makeTypeArray(type[] types ...)
>> {
>>     return types;
>> }
>>
>> import std.algorithm;
>>
>> enum type[] types = makeTypeArray(int, uint, long, ulong);
>> enum size4 = types.filter!((type a) { return a.sizeof == 4; } );
>> pragma(msg, () {
>>     type[] result = [];
>>     foreach(t;size4)
>>     {
>>         result ~= t;
>>     }
>>     return result;
>> }().tupleof);
>> // outputs: tuple((int), (uint))
>
> Nice!
>
> Is there an issue with `std.array.array`, or you just prefer manually converting the range to an array? Btw, dmd can evaluate ranges at compile-time (e.g. in static foreach), so .tupleof could potentially also do that (convert both ranges and arrays of types to a tuples).

Indeed there is an issue with std.array.array.

It seems to want to convert __type[] into void[] or something.
Which makes some template constraint fail.
__type[] to void[] cannot be implemented because strictly speaking the __type[] doesn't hold any data.

I think this can be fixed, by pretending there to be data, however than I loose other nice properties such as __type.sizeof == 0;

So I will likely need to find a different way.
October 11, 2020
On Sunday, 11 October 2020 at 10:19:56 UTC, Stefan Koch wrote:
> On Sunday, 11 October 2020 at 06:22:26 UTC, Petar Kirov [ZombineDev] wrote:
>>
>> Is there an issue with `std.array.array`, or you just prefer manually converting the range to an array? Btw, dmd can evaluate ranges at compile-time (e.g. in static foreach), so .tupleof could potentially also do that (convert both ranges and arrays of types to a tuples).
>
> Indeed there is an issue with std.array.array.
>
> ...

I found out what happens.
This is funky, so fasten your seatbelts :)

Here is the reproducible case:

---
@property ref inout(T) front(T)(return scope inout(T)[] a) @safe pure nothrow @nogc
// if (!isAutodecodableString!(T[]) && !is(T[] == void[])) commented out to avoid deps
{
    assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
    return a[0];
}


template ElementType(R)
{
    pragma(msg, "R: ", R, ", R.init: ", R.init, ", typeof(R.init.front): ", typeof(R.init.front) );

    static if (is(typeof(R.init.front.init) T))
        alias ElementType = T;
    else
        alias ElementType = void;
}

pragma(msg, is(ElementType!(__type[]) == void));
pragma(msg, is(ElementType!(int[]) == void));
---

Which prints:
R: __type[], R.init: null, typeof(R.init.front): __type
true
R: int[], R.init: null, typeof(R.init.front): int
false

That tells us that the front wrapper works correctly.
range __type[] correctly returns a __type;
so R.init.front is a variable of type __type
which makes R.init.front.init be the type __emptyType.
the bug is that because __emptyType is a type

typeof(__emptyType) returns void, which is consistent with how the language has treated types before type functions (they didn't have a type).

So all I have to do is to teach that the type of any type is __type.

And then everything will work!
October 11, 2020
On Sunday, 11 October 2020 at 13:49:20 UTC, Stefan Koch wrote:
>
> So all I have to do is to teach that the type of any type is __type.
>
> And then everything will work!

Turns out that is not the case now array fails with:
phobos/std/conv.d(4529): Error: constructor std.conv.emplaceRef!(__type, __type, __type).emplaceRef.S.this(ref __type _param_0) is not callable using argument types ((__type))

I believe this is an implicit conversion problem ...

Seriously how complicated is phobos ... all you need to do is a foreach loop.
What does std.conv.emplaceRef have to do with it?

remember the code I want to compile is:
---
import std.algorithm;
import std.range;

enum type[] types = makeTypeArray(int, uint, long, ulong);
enum size4 = types.filter!((type a) { return a.sizeof == 4; } ).array;
---

and now I worrying about std.conv.emplaceRef ?

October 11, 2020
On Sunday, 11 October 2020 at 15:46:19 UTC, Stefan Koch wrote:
> On Sunday, 11 October 2020 at 13:49:20 UTC, Stefan Koch wrote:
>>
>> So all I have to do is to teach that the type of any type is __type.
>>
>> And then everything will work!
>
> Turns out that is not the case now array fails with:
> phobos/std/conv.d(4529): Error: constructor std.conv.emplaceRef!(__type, __type, __type).emplaceRef.S.this(ref __type _param_0) is not callable using argument types ((__type))
>
> I believe this is an implicit conversion problem ...

Wow this is so strange ...
lvalue to ref conversion works just fine.

The code below works ... but what else could be going on here?
---
alias type = __type;

type ret(type x)
{
    alias y = x;
    y = passthrough(y);
    return y;
}

type passthrough(ref type y)
{
    return y;
}

pragma(msg, ret(int)); // prints int
---



October 11, 2020
On 11.10.20 17:46, Stefan Koch wrote:
> On Sunday, 11 October 2020 at 13:49:20 UTC, Stefan Koch wrote:
>>
>> So all I have to do is to teach that the type of any type is __type.
>>
>> And then everything will work!
> 
> Turns out that is not the case now array fails with:
> phobos/std/conv.d(4529): Error: constructor std.conv.emplaceRef!(__type, __type, __type).emplaceRef.S.this(ref __type _param_0) is not callable using argument types ((__type))
> 
> I believe this is an implicit conversion problem ...

Probably the compiler thinks that you are calling the function with an rvalue:

---
void foo(ref int){}
void main(){ foo(2); }
---
test.d(2): Error: function `test.foo(ref int _param_0)` is not callable using argument types `(int)`
---
October 12, 2020
On Sunday, 11 October 2020 at 16:53:25 UTC, Timon Gehr wrote:
> On 11.10.20 17:46, Stefan Koch wrote:
>> On Sunday, 11 October 2020 at 13:49:20 UTC, Stefan Koch wrote:
>>>
>>> So all I have to do is to teach that the type of any type is __type.
>>>
>>> And then everything will work!
>> 
>> Turns out that is not the case now array fails with:
>> phobos/std/conv.d(4529): Error: constructor std.conv.emplaceRef!(__type, __type, __type).emplaceRef.S.this(ref __type _param_0) is not callable using argument types ((__type))
>> 
>> I believe this is an implicit conversion problem ...
>
> Probably the compiler thinks that you are calling the function with an rvalue:
>
> ---
> void foo(ref int){}
> void main(){ foo(2); }
> ---
> test.d(2): Error: function `test.foo(ref int _param_0)` is not callable using argument types `(int)`
> ---

Thanks for the pointer.

I hope to fix this bug soon.