www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Better way to compromise on the lack of template alias resolution

reply Elfstone <elfstone yeah.net> writes:
```D
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.

```D
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.
Mar 14 2023
next sibling parent reply ionkare <none y.com> writes:
On Tuesday, 14 March 2023 at 10:19:24 UTC, Elfstone wrote:
 ```D
 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.

 ```D
 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** ```D // 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; } ```
Mar 14 2023
parent Elfstone <elfstone yeah.net> writes:
On Tuesday, 14 March 2023 at 17:57:38 UTC, ionkare wrote:
 On Tuesday, 14 March 2023 at 10:19:24 UTC, Elfstone wrote:
 ```D
 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.

 ```D
 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** ```D // 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? ```D 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.
Mar 14 2023
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
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`: ```d 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 } ```
Mar 15 2023
parent Elfstone <elfstone yeah.net> writes:
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`: ```d 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. :(
Mar 15 2023