Jump to page: 1 25  
Page
Thread overview
Does `is` expression with template alias need fixing.
Mar 15, 2023
Elfstone
Mar 15, 2023
SHOO
Mar 16, 2023
Elfstone
Mar 17, 2023
Elfstone
Mar 18, 2023
Elfstone
Mar 21, 2023
FeepingCreature
Mar 21, 2023
Dom Disc
Mar 21, 2023
FeepingCreature
Mar 21, 2023
Nick Treleaven
Mar 21, 2023
FeepingCreature
Mar 22, 2023
Elfstone
Mar 22, 2023
Elfstone
Mar 22, 2023
FeepingCreature
Mar 22, 2023
Elfstone
Mar 22, 2023
zjh
Mar 22, 2023
zjh
Mar 22, 2023
jmh530
Mar 22, 2023
FeepingCreature
Mar 23, 2023
Elfstone
Mar 27, 2023
Timon Gehr
Mar 28, 2023
Elfstone
Mar 28, 2023
Elfstone
Mar 22, 2023
FeepingCreature
Mar 22, 2023
FeepingCreature
Mar 22, 2023
FeepingCreature
Mar 23, 2023
Elfstone
Mar 23, 2023
kdevel
Mar 24, 2023
FeepingCreature
It's basically Hindley-Milner.
Mar 24, 2023
FeepingCreature
Mar 24, 2023
FeepingCreature
Mar 24, 2023
kdevel
Mar 24, 2023
jmh530
Mar 25, 2023
Elfstone
Mar 24, 2023
Elfstone
Mar 24, 2023
jmh530
Mar 22, 2023
jmh530
Mar 22, 2023
zjh
Mar 15, 2023
jmh530
Mar 16, 2023
Elfstone
Mar 16, 2023
jmh530
Mar 17, 2023
Elfstone
March 15, 2023
struct Matrix(S, size_t M, size_t N)
{
}

alias Vec3(S) = Matrix!(S, 3, 1);

void foo(U)(U v) if (is(U == Vec3!S, S))
{
}

void bar(U)(Vec3!U v) {
}

void main()
{
    import std.stdio;

    Vec3!float v;
    writeln(is(typeof(v) == Vec3!S, S)); // false
    // bar(v); // Error, no bar callable using Matrix!(float, 3, 1). huh!
    // foo(v); // Error, doesn't satisfy constraint.
}

*This is related to DIP1023.
Since we can't use template alias parameters at the moment, how about making writing a constraint more straightforward?

Honestly, this looks like a bugged design:

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

I can live with macros than this.

I have no idea how the compiler works, but I have the feeling fixing is also fixes template alias parameters but anyways, even if I 'm OK with the excuse that "constraints are enough", I don't like the idea of writing Matrix!(S, 3, 1) a second time to create the constraint.

March 15, 2023

On Wednesday, 15 March 2023 at 06:47:38 UTC, Elfstone wrote:

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

I recently faced a similar problem.

import std;
static assert(isInstanceOf!(Array, Array!char)); // true
static assert(isInstanceOf!(Regex, Regex!char)); // false
March 15, 2023

On Wednesday, 15 March 2023 at 06:47:38 UTC, Elfstone wrote:

>

[snip]
void main()
{
import std.stdio;

Vec3!float v;
writeln(is(typeof(v) == Vec3!S, S)); // false

The problem is that typeof(v) gets re-written very quickly by the compiler to Matrix!(float, 3, 1), but the compiler can't tell that a Matrix!(float, 3, 1) is actually a Vec3!S for some generic S (it can't figure out what S should be). For a specific S it can. For instance writeln(is(typeof(v) == Vec3!float)); prints true. So something like

void foo(U)(U v) if (is(U == Vec3!float) || is(U == Vec3!double)) {}

works, even though it is more awkward.

What we need is some way to inform the compiler of the reverse, i.e. that a Matrix!(float, 3, 1) is also a Vec3!float. I had sketched out an idea in the comments on issue 1807 [1], but it was rather half-baked and I'm not sure that's the right way to go. The underlying issue is that you need some kind of way to tell the compiler about the mapping from some concrete type to the template alias.

[1] https://issues.dlang.org/show_bug.cgi?id=1807

March 16, 2023

On Wednesday, 15 March 2023 at 13:07:53 UTC, jmh530 wrote:

>

On Wednesday, 15 March 2023 at 06:47:38 UTC, Elfstone wrote:

>

[snip]
void main()
{
import std.stdio;

Vec3!float v;
writeln(is(typeof(v) == Vec3!S, S)); // false

The problem is that typeof(v) gets re-written very quickly by the compiler to Matrix!(float, 3, 1), but the compiler can't tell that a Matrix!(float, 3, 1) is actually a Vec3!S for some generic S (it can't figure out what S should be). For a specific S it can. For instance writeln(is(typeof(v) == Vec3!float)); prints true. So something like

void foo(U)(U v) if (is(U == Vec3!float) || is(U == Vec3!double)) {}

works, even though it is more awkward.

What we need is some way to inform the compiler of the reverse, i.e. that a Matrix!(float, 3, 1) is also a Vec3!float. I had sketched out an idea in the comments on issue 1807 [1], but it was rather half-baked and I'm not sure that's the right way to go. The underlying issue is that you need some kind of way to tell the compiler about the mapping from some concrete type to the template alias.

[1] https://issues.dlang.org/show_bug.cgi?id=1807

Can't the compiler also rewrite or expand Vec3!S to Matrix!(S, 3, 1) then comfortably evaluate

is(Matrix!(float, 3, 1) == Matrix!(S, 3, 1), S) // true

?

It looks easier than the reverse approach, but again I don't know anything about D compiler.

It'd be better if the compiler would just report an error: "don't you ever put template alias in is(...)". The current behaviour is confusing and of zero use to anyone.

March 16, 2023

On Wednesday, 15 March 2023 at 11:59:00 UTC, SHOO wrote:

>

On Wednesday, 15 March 2023 at 06:47:38 UTC, Elfstone wrote:

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

I recently faced a similar problem.

import std;
static assert(isInstanceOf!(Array, Array!char)); // true
static assert(isInstanceOf!(Regex, Regex!char)); // false

The compiler should at least report it as an error: is cannot handle template alias.

March 16, 2023

On Thursday, 16 March 2023 at 01:57:34 UTC, Elfstone wrote:

>

[snip]

Can't the compiler also rewrite or expand Vec3!S to Matrix!(S, 3, 1) then comfortably evaluate

is(Matrix!(float, 3, 1) == Matrix!(S, 3, 1), S) // true

?

It looks easier than the reverse approach, but again I don't know anything about D compiler.

It'd be better if the compiler would just report an error: "don't you ever put template alias in is(...)". The current behaviour is confusing and of zero use to anyone.

DIP1023 was all about resolving template aliases. The compiler currently treats Vec3!S and Matrix!(S, 3, 1) as different things for the purpose of calling functions. DIP1023 tries to re-write Vec!S into Matrix!(S, 3, 1).

The problem is that

alias Vec3(S) = Matrix!(S, 3, 1);

is actually shorthand for

template Vec3(S) {
    alias Vec3 = Matrix!(S, 3, 1);
}

and it turns out that this is very powerful. Not that you'd want to, but you could just as easily write

template Vec3_alt(S) {
    static if (!is(S == int))
        alias Vec3_alt = Matrix!(S, 3, 1);
    else
        alias Vec3_alt = real;
}

In this case, how do you resolve Vec3!S? It's not as simple as just re-writing it to Matrix!(S, 3, 1).

The solution in DIP1023 only works for a limited--albeit common--subset of the functionality that D supports for template aliases, so it is essentially special casing for template alias deduction. That and running up against the question of "why not just use template constraints", it struggled to gain support.

March 16, 2023

On 3/16/23 12:10 AM, Elfstone wrote:

>

On Wednesday, 15 March 2023 at 11:59:00 UTC, SHOO wrote:

>

On Wednesday, 15 March 2023 at 06:47:38 UTC, Elfstone wrote:

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

I recently faced a similar problem.

import std;
static assert(isInstanceOf!(Array, Array!char)); // true
static assert(isInstanceOf!(Regex, Regex!char)); // false

The compiler should at least report it as an error: is cannot handle template alias.

It can't see that.

The issue is that you are looking through a one-way window. In the general case, the compiler can't solve the puzzle, because it doesn't know the relationship between the template and the thing it gets:

alias Foo(T) = int;

// the following are equivalent to the compiler
is(Foo!float == Foo!T, T);
is(int == Foo!T, T);

How is the compiler supposed to figure out what T you used? By the time it sees the type, it's coming in as int, the alias template itself is completely gone.

Now, I believe the compiler could make a special case for simple aliases, but the rules have to be defined, and the language designers need to agree to add it.

It is a frustrating limitation. One I've brought up myself almost 16 years ago: https://issues.dlang.org/show_bug.cgi?id=1653

I hope some day someone can find a nice way to solve it, at least for IFTI.

-Steve

March 17, 2023

On Friday, 17 March 2023 at 00:40:02 UTC, Steven Schveighoffer wrote:

>

On 3/16/23 12:10 AM, Elfstone wrote:

>

On Wednesday, 15 March 2023 at 11:59:00 UTC, SHOO wrote:

>

On Wednesday, 15 March 2023 at 06:47:38 UTC, Elfstone wrote:

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

I recently faced a similar problem.

import std;
static assert(isInstanceOf!(Array, Array!char)); // true
static assert(isInstanceOf!(Regex, Regex!char)); // false

The compiler should at least report it as an error: is cannot handle template alias.

It can't see that.

The issue is that you are looking through a one-way window. In the general case, the compiler can't solve the puzzle, because it doesn't know the relationship between the template and the thing it gets:

alias Foo(T) = int;

// the following are equivalent to the compiler
is(Foo!float == Foo!T, T);
is(int == Foo!T, T);

How is the compiler supposed to figure out what T you used? By the time it sees the type, it's coming in as int, the alias template itself is completely gone.

Now, I believe the compiler could make a special case for simple aliases, but the rules have to be defined, and the language designers need to agree to add it.

It is a frustrating limitation. One I've brought up myself almost 16 years ago: https://issues.dlang.org/show_bug.cgi?id=1653

I hope some day someone can find a nice way to solve it, at least for IFTI.

-Steve

Perhaps the compiler doesn't have to completely erase Foo!float before it can solve the equation? I don't know. It definitely looks easy to solve.

Again the current behaviour is of no use to anyone, and the compiler lets the code pass without warning is not OK. Whenever someone use a template alias (which s/he may not know is an alias) in an is expression, or as a function parameter, it should report an error, or warning, whatever.

SHOO's case is even more intolerable. Do you expect the user to care about the hidden fact that Regex is an alias, and isInstanceOf can't do its job because Regex is an alias, all because is doesn't work with template aliases?

March 17, 2023

On Thursday, 16 March 2023 at 12:51:39 UTC, jmh530 wrote:

>

On Thursday, 16 March 2023 at 01:57:34 UTC, Elfstone wrote:

>

[snip]

Can't the compiler also rewrite or expand Vec3!S to Matrix!(S, 3, 1) then comfortably evaluate

is(Matrix!(float, 3, 1) == Matrix!(S, 3, 1), S) // true

?

It looks easier than the reverse approach, but again I don't know anything about D compiler.

It'd be better if the compiler would just report an error: "don't you ever put template alias in is(...)". The current behaviour is confusing and of zero use to anyone.

DIP1023 was all about resolving template aliases. The compiler currently treats Vec3!S and Matrix!(S, 3, 1) as different things for the purpose of calling functions. DIP1023 tries to re-write Vec!S into Matrix!(S, 3, 1).

The problem is that

alias Vec3(S) = Matrix!(S, 3, 1);

is actually shorthand for

template Vec3(S) {
    alias Vec3 = Matrix!(S, 3, 1);
}

and it turns out that this is very powerful. Not that you'd want to, but you could just as easily write

template Vec3_alt(S) {
    static if (!is(S == int))
        alias Vec3_alt = Matrix!(S, 3, 1);
    else
        alias Vec3_alt = real;
}

In this case, how do you resolve Vec3!S? It's not as simple as just re-writing it to Matrix!(S, 3, 1).

The solution in DIP1023 only works for a limited--albeit common--subset of the functionality that D supports for template aliases, so it is essentially special casing for template alias deduction. That and running up against the question of "why not just use template constraints", it struggled to gain support.

Hm, maybe D should at least be able to resolve limited simple cases such as mine, and for cases it can't, report an error or warning.

Or just give up and report an error whenever it sees a template alias in is expression, because currently the result is just nonsense.

Just look at SHOO's code. What would a new user think when s/he finally finds out isInstanceOf doesn't work as expected, because Regex is an alias, and isInstanceOf internally uses is to resolve something it just can't? I know what I think: there should be an error message.

For every alias I create, I have to create a matching constraint for it, that's just sad.

alias Vec2(S) = Matrix!(S, 2, 1);
enum isVec2(V) = is(V == Matrix!(S, 2, 1), S);
alias Vec3(S) = Matrix!(S, 3, 1);
enum isVec3(V) = is(V == Matrix!(S, 3, 1), S);
alias Vec4(S) = Matrix!(S, 4, 1);
enum isVec4(V) = is(V == Matrix!(S, 4, 1), S);
March 17, 2023

On 3/17/23 1:19 AM, Elfstone wrote:

>

Perhaps the compiler doesn't have to completely erase Foo!float before it can solve the equation? I don't know. It definitely looks easy to solve.

It looks easy to solve, until you realize that the part that has to solve it doesn't see the same thing.

It's like trying to work backwards that a C preprocessor macro was used after the macro is done rewriting the code.

I get what you are saying, but there will always be an edge where the compiler just can't figure it out, and so, some confusion is going to happen.

>

Again the current behaviour is of no use to anyone, and the compiler lets the code pass without warning is not OK. Whenever someone use a template alias (which s/he may not know is an alias) in an is expression, or as a function parameter, it should report an error, or warning, whatever.

It might be possible, it might not. The compiler doesn't know that a template is an alias until it instantiates the template. To us, reading the code, it is obvious. But internally it doesn't store things that way.

>

SHOO's case is even more intolerable. Do you expect the user to care about the hidden fact that Regex is an alias, and isInstanceOf can't do its job because Regex is an alias, all because is doesn't work with template aliases?

SHOO's case is even more unsolvable. isInstanceOf is itself a template, and therefore cached. Per the D language rules, aliases cannot cause a different instantiation.

alias Foo(T) = T;
alias Bar(T) = T;

pragma(msg, isInstanceOf!(int, Foo)); // Should this be true?

// these are now cached, since they are equivalent to the first
// Should the evaluation depend on which order you call these?
pragma(msg, isInstanceOf!(Bar!T, Foo));
pragma(msg, isInstanceOf!(Foo!T, Foo));

-Steve

« First   ‹ Prev
1 2 3 4 5