Jump to page: 1 2 3
Thread overview
I want to create my own Tuple type
Jan 11, 2021
Paul Backus
Jan 11, 2021
Paul Backus
Jan 11, 2021
Paul Backus
Jan 11, 2021
Paul Backus
Jan 11, 2021
Paul Backus
Jan 11, 2021
Paul Backus
Jan 12, 2021
sighoya
January 10, 2021
I want to create my own Tuple type, and I don't like the messy implementation of the one in D's standard lib, or the one in Clang++'s standard lib. The concept is very simple so it is disheartening if it cannot be done in a simple way that does not impact compile times... :-/

The requirements are:

1. It should not lead to slower compile times than fixed arity templates (if so, then I would just list all sizes from 0..64 instead).

2. If all types are similar then it should be implemented as a static array with indexing. If not, then all fields should have the names __0, __1 etc.


Something along the lines of, but not with fixed arity:


struct Tuple(){}

struct Tuple(T0){
    T0[1] __v;
    const ref opIndex(size_t i){ return __v[i]; }
}

struct Tuple(T0,T1){
    static if (is(T0==T1)) {
        T0[2] __v;
        this(T0 a, T1 b){__v[0]=a; __v[1]=b; }
        const ref opIndex(size_t i){ return __v[i]; }
    } else {
        T0 __0;
        T1 __1;
    }
}

auto _tuple(Ts...)(Ts args){
    return __Tuple!Ts(args);
}


January 11, 2021
On Sunday, 10 January 2021 at 16:52:30 UTC, Ola Fosheim Grøstad wrote:
> I want to create my own Tuple type, and I don't like the messy implementation of the one in D's standard lib, or the one in Clang++'s standard lib. The concept is very simple so it is disheartening if it cannot be done in a simple way that does not impact compile times... :-/
>
> The requirements are:
>
[...]
>
> 2. If all types are similar then it should be implemented as a static array with indexing. If not, then all fields should have the names __0, __1 etc.

Why are these particular implementation details important to you?
January 11, 2021
On Monday, 11 January 2021 at 01:49:26 UTC, Paul Backus wrote:
> Why are these particular implementation details important to you?

It is for object.d.

I want to allow fast runtime indexing if all elements are of the same type.

If the types are different I want static indexing, so the plan is to resolve failed lookup as __0 etc by modifying the compiler.
January 11, 2021
On Monday, 11 January 2021 at 05:44:19 UTC, Ola Fosheim Grostad wrote:
> On Monday, 11 January 2021 at 01:49:26 UTC, Paul Backus wrote:
>> Why are these particular implementation details important to you?
>
> It is for object.d.
>
> I want to allow fast runtime indexing if all elements are of the same type.

static if (allSameType) {
    auto opIndex(size_t i) {
        switch (i) {
            static foreach (j; 0 .. Types.length) {
                case j: return this.expand[j];
            }
            default: assert(0); // or throw RangeError
        }
    }
}

Any decent compiler will turn this into `return this.expand[i]`.

> If the types are different I want static indexing, so the plan is to resolve failed lookup as __0 etc by modifying the compiler.

You can just fall back to `alias expand this` like Phobos's Tuple does in this case. No compiler modification needed.
January 11, 2021
On Monday, 11 January 2021 at 05:59:03 UTC, Paul Backus wrote:
> static if (allSameType) {
>     auto opIndex(size_t i) {
>         switch (i) {
>             static foreach (j; 0 .. Types.length) {
>                 case j: return this.expand[j];
>             }
>             default: assert(0); // or throw RangeError
>         }
>     }
> }
>
> Any decent compiler will turn this into `return this.expand[i]`.

Maybe, I would then have to test for release mode and replace default: faulting with "unreachable"...

I guess I won't know how this works out without testing, but it would in general be nice to be sure that a reinterpret cast to a static array would work.

>> If the types are different I want static indexing, so the plan is to resolve failed lookup as __0 etc by modifying the compiler.
>
> You can just fall back to `alias expand this` like Phobos's Tuple does in this case. No compiler modification needed.

I though maybe it would be nice in general to be able to create static indexed type by having a special field name pattern, but I will have a another look at staticMap (I don't really want the full staticMap into object.d though).

I am a bit worried about compile time implications as I use tuples more and more in my own code, and expect that is a common trend...

Maybe one could special case arity 0,1,2,3,4,5,6,7,8 and use a more generic template for 9 and up.

January 11, 2021
On Monday, 11 January 2021 at 09:42:39 UTC, Ola Fosheim Grøstad wrote:
> I though maybe it would be nice in general to be able to create static indexed type by having a special field name pattern, but I will have a another look at staticMap (I don't really want the full staticMap into object.d though).

This is the core of staticMap, I find it problematic to do this kind of string mixin in object.d:

private enum staticMapExpandFactor = 150;
private string generateCases()
{
    string[staticMapExpandFactor] chunks;
    chunks[0] = q{};
    static foreach (enum i; 0 .. staticMapExpandFactor - 1)
        chunks[i + 1] = chunks[i] ~ `F!(Args[` ~ i.stringof ~ `]),`;
    string ret = `AliasSeq!(`;
    foreach (chunk; chunks)
        ret ~= `q{alias staticMap = AliasSeq!(` ~ chunk ~ `);},`;
    return ret ~ `)`;
}
private alias staticMapBasicCases = AliasSeq!(mixin(generateCases()));




January 11, 2021
On Monday, 11 January 2021 at 09:42:39 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 11 January 2021 at 05:59:03 UTC, Paul Backus wrote:
>> You can just fall back to `alias expand this` like Phobos's Tuple does in this case. No compiler modification needed.
>
> I though maybe it would be nice in general to be able to create static indexed type by having a special field name pattern, but I will have a another look at staticMap (I don't really want the full staticMap into object.d though).

I have no idea why you're bringing up staticMap here. The simplest way to create a tuple's fields is to use type sequence instantiation [1], like Phobos does:

struct Tuple(Types...)
{
    Types expand;

    // ...
}

You can then access the individual fields with `expand[i]`, where `i` is any compile-time evaluable integer expression. Adding `alias expand this` (as Phobos does) allows the indexing to be performed directly on the tuple, without having to write `.expand` first.

To handle dynamic vs. static indexing you can use a simple static if:

static if (allSameTypes) {
    auto opIndex(size_t i) {
        // ...
    }
} else {
    alias expand this;
}

[1] https://dlang.org/articles/ctarguments.html#type-seq-instantiation
January 11, 2021
On Monday, 11 January 2021 at 14:03:39 UTC, Paul Backus wrote:
> On Monday, 11 January 2021 at 09:42:39 UTC, Ola Fosheim Grøstad wrote:
>> On Monday, 11 January 2021 at 05:59:03 UTC, Paul Backus wrote:
>>> You can just fall back to `alias expand this` like Phobos's Tuple does in this case. No compiler modification needed.
>>
>> I though maybe it would be nice in general to be able to create static indexed type by having a special field name pattern, but I will have a another look at staticMap (I don't really want the full staticMap into object.d though).
>
> I have no idea why you're bringing up staticMap here. The simplest way to create a tuple's fields is to use type sequence instantiation [1], like Phobos does:

Ok, thanks. I guess typecons only use staticMap because it allows for named fields.

January 11, 2021
On Monday, 11 January 2021 at 14:03:39 UTC, Paul Backus wrote:
>     alias expand this;

Hm... this does not allow me protect the fields from being changed. I also cannot use const since it is transitive and would make it impossible to return two references to mutable objects?

Basically, the tuple itself should be immutable, but not the objects being referenced. I guess I could run over the types and add const if they are not references?

January 11, 2021
On Monday, 11 January 2021 at 14:51:29 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 11 January 2021 at 14:03:39 UTC, Paul Backus wrote:
>>     alias expand this;
>
> Hm... this does not allow me protect the fields from being changed. I also cannot use const since it is transitive and would make it impossible to return two references to mutable objects?
>
> Basically, the tuple itself should be immutable, but not the objects being referenced. I guess I could run over the types and add const if they are not references?

But that would leave references mutable... so not the best solution. I kinda like the flexibility of __0, __1 and that it maps nicely to a regular struct.
« First   ‹ Prev
1 2 3