Bug 16486 – Compiler see template alias like a separate type in template function definition

Status
RESOLVED
Resolution
DUPLICATE
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-09-11T16:12:35Z
Last change time
2020-12-24T02:31:10Z
Assigned to
No Owner
Creator
Sky Thirteenth
See also
https://issues.dlang.org/show_bug.cgi?id=1807

Comments

Comment #0 by sky.13th.95 — 2016-09-11T16:12:35Z
For example, here the type: ``` struct TestType(T, size_t size) { T[size] data; } ``` And, for some reason, We want to have some aliases on it: ``` alias TestAliasA = TestType; alias TestAliasB(T) = TestType!(T, 3); ``` Then We, obviously, somehow use them: ``` void testFunctionA(T)(TestType!(T, 3) arg) { writeln( arg ); } void testFunctionB(T)(TestAliasA!(T, 3) arg) { writeln( arg ); } void testFunctionC(T)(TestAliasB!T arg) { writeln( arg ); } ``` But there is the problem with usage of `testFunctionC`. It cause compiler error. It just simply can not recognize that TestAliasB!T and TestType!(int, 3) is the same type, rather than different. Here complete example: https://dpaste.dzfl.pl/2c8e1c350182
Comment #1 by ag0aep6g — 2016-09-11T22:37:57Z
Reduced to the core: ---- struct TestType(T) {} alias TestAlias(T) = TestType!T; void testFunction(T)(TestAlias!T arg) {} void main() { TestAlias!int testObj; testFunction(testObj); /* "cannot deduce function from argument types !()(TestType!int)" */ } ---- I don't think this is supposed to work. It works when testFunction's parameter is TestType!T, because testObj's type (TestType!int/TestAlias!int) carries the information that it's an instantiation of template TestType with argument int. But the compiler has no simple way of telling how TestType!int relates to TestAlias!T. For example, TestAlias could be defined like this: ---- template TestAlias(T) { static if (is(T == float)) alias TestAlias = TestType!int; else alias TestAlias = string; } ---- With that, testFunction(TestType!int.init) would have to result in T = float. And with testFunction("") the compiler would have multiple choices for T. With the original TestAlias it's more straight-forward, but the compiler would still have to analyze TestAlias's implementation. That's probably not feasible (maybe impossible) in the general case. Maybe simple cases could be supported. But that would be an enhancement request, I think. And then there's always the question of where to draw the line, and if it's not better to minimize surprises by just rejecting any such code.
Comment #2 by sky.13th.95 — 2016-09-12T18:23:55Z
(In reply to ag0aep6g from comment #1) > Reduced to the core: > > ---- > struct TestType(T) {} > alias TestAlias(T) = TestType!T; > void testFunction(T)(TestAlias!T arg) {} > > void main() > { > TestAlias!int testObj; > testFunction(testObj); /* "cannot deduce function from argument types > !()(TestType!int)" */ > } > ---- > > I don't think this is supposed to work. > > It works when testFunction's parameter is TestType!T, because testObj's type > (TestType!int/TestAlias!int) carries the information that it's an > instantiation of template TestType with argument int. > > But the compiler has no simple way of telling how TestType!int relates to > TestAlias!T. For example, TestAlias could be defined like this: > > ---- > template TestAlias(T) > { > static if (is(T == float)) alias TestAlias = TestType!int; > else alias TestAlias = string; > } > ---- > > With that, testFunction(TestType!int.init) would have to result in T = > float. And with testFunction("") the compiler would have multiple choices > for T. > > With the original TestAlias it's more straight-forward, but the compiler > would still have to analyze TestAlias's implementation. That's probably not > feasible (maybe impossible) in the general case. > > Maybe simple cases could be supported. But that would be an enhancement > request, I think. And then there's always the question of where to draw the > line, and if it's not better to minimize surprises by just rejecting any > such code. OK, I clearly understand the cost which it may take. But, don't You think that this "limitation" is weird? All of possible performance drop it's problem nor of compiler, nor of language, but of programmer, who wrote this code. It's already possible to construct complex types on compile time, so why We can not do that for template functions too? P.S.: For example, C++ allow this kind of calculations. Yes, in C++ it slow and ugly looking, but it's not a fault of a concept. It's problem of realization.
Comment #3 by schveiguy — 2016-09-12T18:54:14Z
The issue is that the compiler doesn't replace the alias until AFTER instantiation. It should be able to see that: testFunctionC(T)(TestAliasB!T arg) is the same as testFunctionC(T)(TestType!(T, 3) arg) and reduce basically to the same thing as testFunctionA Still definitely an enhancement, as there is no definition of how the compiler will work backwards through template instantiations. It may be a duplicate, I distinctly remember wishing for this kind of thing back when D2 was in infancy.
Comment #4 by sky.13th.95 — 2016-09-13T20:55:12Z
(In reply to Steven Schveighoffer from comment #3) > The issue is that the compiler doesn't replace the alias until AFTER > instantiation. > > It should be able to see that: > > testFunctionC(T)(TestAliasB!T arg) > > is the same as > > testFunctionC(T)(TestType!(T, 3) arg) > > and reduce basically to the same thing as testFunctionA > > Still definitely an enhancement, as there is no definition of how the > compiler will work backwards through template instantiations. > > It may be a duplicate, I distinctly remember wishing for this kind of thing > back when D2 was in infancy. Actually, in my opinion, as it acts now, looks wrong, because this feature is not used at full power. We can use templates and template alias, while declare variables, but can't do the same thing while describe arguments for other templates(no matter is it type or function). Don't you feel wrong about it? The meaning of this features, is to simplify things. But in this case we need to write something like this: ``` auto foo( That )( What.TheHell!(is(That : Thing) && How!(IShould!(Use!That))) arg ) { //... } ``` Rather then just write down this: ``` auto foo( That )( CatInABag!That arg ) { //... } ``` Of course, now I'm exaggerating things, but still it can be pretty useful feature.
Comment #5 by ag0aep6g — 2016-09-13T21:46:00Z
(In reply to Sky Thirteenth from comment #4) > it can be pretty useful feature. Sure. I don't think anyone disputes that it could be a useful feature. So we keep the issue open as an enhancement request. It's not a bug, because, as far as I know, there has been no intention to support the feature, yet. That is, the language specification doesn't say that it should work, and there's no (buggy) code in the compiler that attempts to do it.
Comment #6 by sky.13th.95 — 2016-09-13T21:55:21Z
(In reply to ag0aep6g from comment #5) > (In reply to Sky Thirteenth from comment #4) > > it can be pretty useful feature. > > Sure. I don't think anyone disputes that it could be a useful feature. So we > keep the issue open as an enhancement request. > > It's not a bug, because, as far as I know, there has been no intention to > support the feature, yet. That is, the language specification doesn't say > that it should work, and there's no (buggy) code in the compiler that > attempts to do it. Then, OK. So, at least now I will know about it. And also know that this feature may appear later, in a future. Thank You for Your time spend on this. =)
Comment #7 by ag0aep6g — 2018-04-17T16:08:26Z
*** This issue has been marked as a duplicate of issue 10884 ***