Thread overview
Better way to compromise on the lack of template alias resolution stuff?
Mar 14, 2023
Elfstone
Mar 14, 2023
ionkare
Mar 15, 2023
Elfstone
Mar 15, 2023
Paul Backus
Mar 16, 2023
Elfstone
March 14, 2023
struct Matrix(S, size_t M, size_t N)
{
}

alias Vector(S, size_t N) = Matrix!(S, N, 1);

enum isVector(V) = is(V == Vector!(S, N), S, size_t N); // it doesn't work

enum isVectorCorrect(V) = is(V == Matrix!(U, N, 1), U, size_t N); // the "correct" way and how much I like to REPEAT myself!

void foo(U)(Vector!(U, 3) a)
{
}

void bar(U)(U a) if (isVector!U)
{
}

void main()
{
    import std.stdio;

    Vector!(float, 3) v;
    foo(v); // Error: none of the overloads of template `app.doSomething` are callable using argument types `!()(Matrix!(float, 3LU, 1LU))
    bar(v); // failed constraint isVector!U
}

I went back to some of my old code and couldn't stand what I had ended up with - If I already have a well-defined Vector, why do I have to write extra code to implement isVector, and use isVector instead of simply declaring the param to be Vector?

But that's simply the current state: it looks like DIP1023 isn't going anywhere, and I'm not a compiler expert.

Note that I had to repeat Matrix!(S, N, 1) to for both Vector and isVector.

Is there a way around this?!

--

It can get worse.

alias Vec2(S) = Vector!(S, 2);
alias Vec3(S) = Vector!(S, 3);
enum isVec3(V) = is(V == Matrix!(S, 2, 1), S);
enum isVec3(V) = is(V == Matrix!(S, 3, 1), S);
void foobar(U)(U v) if (isVec3!U);

It works, but it hurts my eyes.

March 14, 2023

On Tuesday, 14 March 2023 at 10:19:24 UTC, Elfstone wrote:

>
struct Matrix(S, size_t M, size_t N)
{
}

alias Vector(S, size_t N) = Matrix!(S, N, 1);

enum isVector(V) = is(V == Vector!(S, N), S, size_t N); // it doesn't work

enum isVectorCorrect(V) = is(V == Matrix!(U, N, 1), U, size_t N); // the "correct" way and how much I like to REPEAT myself!

void foo(U)(Vector!(U, 3) a)
{
}

void bar(U)(U a) if (isVector!U)
{
}

void main()
{
    import std.stdio;

    Vector!(float, 3) v;
    foo(v); // Error: none of the overloads of template `app.doSomething` are callable using argument types `!()(Matrix!(float, 3LU, 1LU))
    bar(v); // failed constraint isVector!U
}

I went back to some of my old code and couldn't stand what I had ended up with - If I already have a well-defined Vector, why do I have to write extra code to implement isVector, and use isVector instead of simply declaring the param to be Vector?

But that's simply the current state: it looks like DIP1023 isn't going anywhere, and I'm not a compiler expert.

Note that I had to repeat Matrix!(S, N, 1) to for both Vector and isVector.

Is there a way around this?!

--

It can get worse.

alias Vec2(S) = Vector!(S, 2);
alias Vec3(S) = Vector!(S, 3);
enum isVec3(V) = is(V == Matrix!(S, 2, 1), S);
enum isVec3(V) = is(V == Matrix!(S, 3, 1), S);
void foobar(U)(U v) if (isVec3!U);

It works, but it hurts my eyes.

just a noob seeing if can solve this no idea if this is vaild code

// T int, double, float
// N element
// V number of elements / weight
template Matrix(T, size_t N = 2, size_t V = 1)
{
    struct Matrix
    {
        static if (is(Matrix!(T, N, V)))
        {
            alias enum isVec3 = N == 3;
            alias enum isVec2 = N == 2;

            alias enum isVaildVec = (isVec2 || isVec3);
        }
    }
}

bool foo(T)(Matrix!T element)
{
    return element.isVaildVec;
}

void main()
{
    import std.stdio : writeln;

    // defaults to vec2 of 1
    Matrix!int c;
    c.foo.writeln;
    c.writeln;
}
March 15, 2023

On Tuesday, 14 March 2023 at 17:57:38 UTC, ionkare wrote:

>

On Tuesday, 14 March 2023 at 10:19:24 UTC, Elfstone wrote:

>
struct Matrix(S, size_t M, size_t N)
{
}

alias Vector(S, size_t N) = Matrix!(S, N, 1);

enum isVector(V) = is(V == Vector!(S, N), S, size_t N); // it doesn't work

enum isVectorCorrect(V) = is(V == Matrix!(U, N, 1), U, size_t N); // the "correct" way and how much I like to REPEAT myself!

void foo(U)(Vector!(U, 3) a)
{
}

void bar(U)(U a) if (isVector!U)
{
}

void main()
{
    import std.stdio;

    Vector!(float, 3) v;
    foo(v); // Error: none of the overloads of template `app.doSomething` are callable using argument types `!()(Matrix!(float, 3LU, 1LU))
    bar(v); // failed constraint isVector!U
}

I went back to some of my old code and couldn't stand what I had ended up with - If I already have a well-defined Vector, why do I have to write extra code to implement isVector, and use isVector instead of simply declaring the param to be Vector?

But that's simply the current state: it looks like DIP1023 isn't going anywhere, and I'm not a compiler expert.

Note that I had to repeat Matrix!(S, N, 1) to for both Vector and isVector.

Is there a way around this?!

--

It can get worse.

alias Vec2(S) = Vector!(S, 2);
alias Vec3(S) = Vector!(S, 3);
enum isVec3(V) = is(V == Matrix!(S, 2, 1), S);
enum isVec3(V) = is(V == Matrix!(S, 3, 1), S);
void foobar(U)(U v) if (isVec3!U);

It works, but it hurts my eyes.

just a noob seeing if can solve this no idea if this is vaild code

// T int, double, float
// N element
// V number of elements / weight
template Matrix(T, size_t N = 2, size_t V = 1)
{
    struct Matrix
    {
        static if (is(Matrix!(T, N, V)))
        {
            alias enum isVec3 = N == 3;
            alias enum isVec2 = N == 2;

            alias enum isVaildVec = (isVec2 || isVec3);
        }
    }
}

bool foo(T)(Matrix!T element)
{
    return element.isVaildVec;
}

void main()
{
    import std.stdio : writeln;

    // defaults to vec2 of 1
    Matrix!int c;
    c.foo.writeln;
    c.writeln;
}

This requires coding inside Matrix, while my Matrix is only about Matrix operations.

The thing is that I can create aliases anywhere, outside of the original module. I can use the the aliases everywhere except as template parameters, because D simply won't match template alias parameters, and I could not find a way to create a constraint based on an existing alias, which defeats the supposed meaning and purpose of alias.

I hope some Samaritan in the community will actually "see the value" in this, pick up DIP1023 or push another. Before that happens, if ever, all I can do is restraining myself from using template alias parameters, 'cause it IS in fact broken.

How does anyone see the following code and not call the language bugged?

writeln(is(Vec2!float == Vec2!S, S));  // false

Actually I'd be happy if this code works, because then I can create a constraint based on the alias. But I guess it requires the same machanism to make template alias parameters work.

March 15, 2023

On Tuesday, 14 March 2023 at 10:19:24 UTC, Elfstone wrote:

>

I went back to some of my old code and couldn't stand what I had ended up with - If I already have a well-defined Vector, why do I have to write extra code to implement isVector, and use isVector instead of simply declaring the param to be Vector?

But that's simply the current state: it looks like DIP1023 isn't going anywhere, and I'm not a compiler expert.

Note that I had to repeat Matrix!(S, N, 1) to for both Vector and isVector.

Is there a way around this?!

Currently the best workaround for this is to define Vector as a struct with alias this instead of as an alias:

struct Matrix(S, size_t M, size_t N)
{
    // ...
}

//alias Vector(S, size_t N) = Matrix!(S, N, 1);

struct Vector(S, size_t N)
{
    Matrix!(S, N, 1) data;
    alias data this;

    // forward constructor calls to wrapped object
    this(this This, Args...)(auto ref Args args)
    {
        import core.lifetime: forward;
        data = forward!args;
    }
}

void foo(U)(Vector!(U, 3) a)
{
    import std.stdio;
    writeln("Called with U = ", U.stringof);
}

void main()
{
    Vector!(float, 3) v;
    foo(v); // ok
}
March 16, 2023

On Wednesday, 15 March 2023 at 19:22:32 UTC, Paul Backus wrote:

>

On Tuesday, 14 March 2023 at 10:19:24 UTC, Elfstone wrote:

>

[...]

Currently the best workaround for this is to define Vector as a struct with alias this instead of as an alias:

struct Matrix(S, size_t M, size_t N)
{
    // ...
}

//alias Vector(S, size_t N) = Matrix!(S, N, 1);

struct Vector(S, size_t N)
{
    Matrix!(S, N, 1) data;
    alias data this;

    // forward constructor calls to wrapped object
    this(this This, Args...)(auto ref Args args)
    {
        import core.lifetime: forward;
        data = forward!args;
    }
}

void foo(U)(Vector!(U, 3) a)
{
    import std.stdio;
    writeln("Called with U = ", U.stringof);
}

void main()
{
    Vector!(float, 3) v;
    foo(v); // ok
}

There's a problem with this approach: I'll have to specialize Vector Matrix.opBinary(Vector). I don't plan to separate my Vector from Matrix yet. :(