December 27, 2020
This fails to compile:

  struct Foo(T) {}

  alias Bar(T) = Foo!T;

  void f(T)(Bar!T x) {}

  void main() {
    f(Bar!int());
  }

as the type resolution fails to unify the alias Bar with the type Foo. I think this is a basic type system failure, basic type unification should easily resolve this:

https://www.google.com/search?q=implement+type+unification
https://en.wikipedia.org/wiki/Unification_(computer_science)

Bearophile reported it in 2013:
https://issues.dlang.org/show_bug.cgi?id=10884

And it has been classified as a duplicate of a 2008 issue:
https://issues.dlang.org/show_bug.cgi?id=1807

It has been misclassified as "enhancement", when it actually should be classified as a "critical type system failure".

The problem (or related problems) has been discussed in a DIP and in a pull request and DIP:

https://github.com/dlang/dmd/pull/9778
https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1023.md

When will this issue get the love it deserves? Fixing such in-your-face type system failures ought to be much more important than adding new features, surely?

7-12 years to fix such basic type system functionality is quite a long time considering the many features that has been added in that time period.

(Btw, this works perfectly fine in C++).




December 28, 2020
On Sunday, 27 December 2020 at 13:36:44 UTC, Ola Fosheim Grøstad wrote:
> [snip]

For reference, this was also discussed recently here [1]. I'm not sure if the tone on that thread was the best to push this idea forward, perhaps this one might be a bit better.

-----

To the example you provide, the following does compile

struct Foo(T) {}
alias Bar(T) = Foo!T;
void f(T)(Bar!T x) {}

void main() {
    f!int(Bar!int());
}

In other words, the problem is due to type deduction of alias templates. No type deduction, no problem.

Here's another simple example of using this feature to facilitate the use of something like Concepts:

enum bool check(T) = is(T == float);

template Concept(T, alias U)
{
    static assert(U!T);
    alias Concept = T;
}

void foo(T)(Concept!(T, check) x) { }

void main() {
    Concept!(float, check) x;
    foo(x); //does not compile
    foo!float(x); //does compile
}

ideally you could also use it as in
alias Check(T) = Concept!(T, check);
void foo(T)(Check!(T) x) { }

-----

Reading over the issue [2] again, one of the sticking points that is provided is (without including some of the BlasMatrix-related stuff)

alias PackedUpperTriangularMatrix(T) = Slice!(StairsIterator!(T*, "-"));

void composeLU(T)(
    PackedLowerTriangularMatrix!(const T) l, // First Slice type for Lower Matrix
    PackedUpperTriangularMatrix!(const T) u, // Second Slice type for Lower Matrix
    BlasMatrix!T lu, // Third Slice type for General Matrix
)
    if (is(T == float) && is(T == double))
{
    ...
}

with the alternative

enum isPackedUpperTriangularMatrix(T) = is(T: Slice!(StairsIterator!(U*, "-")), U);

void composeLU(L, U, LU)(L l, U u, LU lu)
    if(isPackedLowerTriangularMatrix!L
       && isPackedUpperTriangularMatrix!U
       && isBlasMatrix!LU
       && /* .. */
    )
{
}

A point that Ilya makes is that you need to fill in the /* .. */, which makes the whole thing become something like

void composeLU(L, U, LU)(L l, U u, LU lu)
    if(isPackedLowerTriangularMatrix!L
       && isPackedUpperTriangularMatrix!U
       && isBlasMatrix!LU
       && (is(Unqual!(ForeachType!L) == float) || is(Unqual!(ForeachType!L) == double)))
       && is(ForeachType!L == ForeachType!U)
       && is(ForeachType!LU == Unqual!(ForeachType!L))
    )
{
}

It really does help make the case for the change when you have to write them all out yourself.

[1] https://forum.dlang.org/post/yobmmccdvbmmbaolehbs@forum.dlang.org
[2] https://github.com/dlang/dmd/pull/9778