Thread overview | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 30, 2017 Bug in D!!! | ||||
---|---|---|---|---|
| ||||
This is quite surprising! public struct S(T) { T s; } interface I { void Go(T)(S!T s); static final I New() { return new C(); } } abstract class A : I { } class C : A { void Go(T)(S!T s) { } } void main() { S!int s; auto c = I.New(); c.Go(s); // fails! //(cast(C)c).Go(s); // Works, only difference is we have made c an explicit C. } https://dpaste.dzfl.pl/dbc5a0663802 Everything works when Go is not templatized(we explicitly make T an int) This is a blocker for me! Can someone open a ticket? |
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to EntangledQuanta | It can't work this way. You can try std.variant. |
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Wednesday, 30 August 2017 at 21:13:19 UTC, Kagamin wrote:
> It can't work this way. You can try std.variant.
Sure it can! What are you talking about! std.variant has nothing to do with it! It works if T is hard coded, so it should work generically. What's the point of templates variables if they can't be used across inheritance?
I could overload Go for each type and hence it should work. There is absolutely no reason why it can't work. Replace T with short, it works, replace T with anything and it works, hence it should work with T.
If you are claiming that the compiler has to make a virtual function for each T, that is nonsense, I only need it for primitives, and there are a finite number of them. I could create overloads for short, int, double, float, etc but why? The whole point of templates is to solve that problem.
Variants do not help.
Openmethods can solve this problem too, but D should be more intelligent than simply writing off all normal use cases because someone thinks something can't be done. How many people thought it was impossible to go to the moon, yet it happened. Anyone can't deny anything, it's such a simple thing to do...
|
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to EntangledQuanta | On Wednesday, August 30, 2017 20:47:12 EntangledQuanta via Digitalmars-d- learn wrote:
> This is quite surprising!
>
> public struct S(T)
> {
> T s;
> }
>
>
> interface I
> {
> void Go(T)(S!T s);
>
> static final I New()
> {
> return new C();
> }
> }
>
> abstract class A : I
> {
>
> }
>
>
> class C : A
> {
> void Go(T)(S!T s)
> {
>
> }
> }
>
>
> void main()
> {
> S!int s;
> auto c = I.New();
>
> c.Go(s); // fails!
> //(cast(C)c).Go(s); // Works, only difference is we have made c
> an explicit C.
>
> }
>
> https://dpaste.dzfl.pl/dbc5a0663802
>
> Everything works when Go is not templatized(we explicitly make T
> an int)
>
>
> This is a blocker for me! Can someone open a ticket?
It is not possible to have a function be both virtual and templated. A function template generates a new function definition every time that it's a called with a new set of template arguments. So, the actual functions are not known up front, and that fundamentally does not work with virtual functions, where the functions need to be known up front, and you get a different function by a look-up for occurring in the virtual function call table for the class. Templates and virtual functions simply don't mix. You're going to have to come up with a solution that does not try and mix templates and virtual functions.
- Jonathan M Davis
|
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to EntangledQuanta | On Wednesday, 30 August 2017 at 20:47:12 UTC, EntangledQuanta wrote: > This is quite surprising! > > public struct S(T) > { > T s; > } > > > interface I > { > void Go(T)(S!T s); > > static final I New() > { > return new C(); > } > } > > abstract class A : I > { > > } > > > class C : A > { > void Go(T)(S!T s) > { > > } > } > > > void main() > { > S!int s; > auto c = I.New(); > > c.Go(s); // fails! > //(cast(C)c).Go(s); // Works, only difference is we have made c an explicit C. > > } > > https://dpaste.dzfl.pl/dbc5a0663802 > > Everything works when Go is not templatized(we explicitly make T an int) > > > This is a blocker for me! Can someone open a ticket? Knock yourself out: https://issues.dlang.org/ Anyone can open tickets for bugs or enhancement requsts. bye, lobo |
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Wednesday, 30 August 2017 at 21:33:30 UTC, Jonathan M Davis wrote:
> On Wednesday, August 30, 2017 20:47:12 EntangledQuanta via Digitalmars-d- learn wrote:
>> This is quite surprising!
>>
>> public struct S(T)
>> {
>> T s;
>> }
>>
>>
>> interface I
>> {
>> void Go(T)(S!T s);
>>
>> static final I New()
>> {
>> return new C();
>> }
>> }
>>
>> abstract class A : I
>> {
>>
>> }
>>
>>
>> class C : A
>> {
>> void Go(T)(S!T s)
>> {
>>
>> }
>> }
>>
>>
>> void main()
>> {
>> S!int s;
>> auto c = I.New();
>>
>> c.Go(s); // fails!
>> //(cast(C)c).Go(s); // Works, only difference is we have made c
>> an explicit C.
>>
>> }
>>
>> https://dpaste.dzfl.pl/dbc5a0663802
>>
>> Everything works when Go is not templatized(we explicitly make T
>> an int)
>>
>>
>> This is a blocker for me! Can someone open a ticket?
>
> It is not possible to have a function be both virtual and templated. A function template generates a new function definition every time that it's a called with a new set of template arguments. So, the actual functions are not known up front, and that fundamentally does not work with virtual functions, where the functions need to be known up front, and you get a different function by a look-up for occurring in the virtual function call table for the class. Templates and virtual functions simply don't mix. You're going to have to come up with a solution that does not try and mix templates and virtual functions.
>
> - Jonathan M Davis
I have a finite number of possible values of T, lets say 3. They are known at compile time, just because you are or D thinks they are not simply means you or D is not trying hard enough. So, saying that virtual methods and templates are not compatible is wrong. Just because you think they are or D thinks they are means you haven't thought about it hard enough.
If I can overload a virtual function to get all my use cases and that is all I need then I **should** be able to do it with templates. Simple as that, if D can't do that then D needs to be enhanced to do so.
e.g.,
class C
{
Go(Primitive!T)(T t);
}
The compiler can realize that T can only be a primitive, and generates all possible combinations of primitives, which is finite. This is doable, it is not impossible, regardless of what you think. It is equivalent to
class C
{
Go(Primitive1 t);
Go(Primitive2 t);
...
Go(PrimitiveN t);
}
In fact, we can use string mixins to generate such code, but it doens't save us trouble, which is what templates are suppose to do in the first place. Just become someone hasn't implemented special cases does not mean it is theoretically impossible to do.
A different syntax would be better
interface I
{
Go(T in [float, double, int])(T t);
}
class C : I
{
Go(T in [float, double, int])(T t) { }
}
which the compiler "unrolls" to
interface I
{
Go(float t);
Go(double t);
Go(int t);
}
class C
{
Go(float t) { }
Go(double t) { }
Go(int t) { }
}
Which, is standard D code. There is nothing wrong with specializing the most common cases.
The point you are trying to making, and not doing a great job, is that the compiler cannot create an unknown set of virtual functions from a single templated virtual function. BUT, when you realize that is what the problem is, the unknown set is the issue NOT templated virtual functions. Make the set known and finite somehow then you have a solution, and it's not that difficult. Just requires some elbow grease.
Primitives are obviously known at compile time so that is a doable special case. Although there will probably be quite a bit of wasted space since each primitive will have a function generated for it for each templated function, that really isn't an issue.
By adding a new syntax in D, we could allow for any arbitrary(but known and finite) set to be used
Go(T in [A,B,C])(T t)
Where A,B,C are known types at compile time. This generates 3 functions and is doable. (should be simple for any D compiler genius to add for testing)
|
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to EntangledQuanta | On Wednesday, August 30, 2017 21:51:57 EntangledQuanta via Digitalmars-d- learn wrote:
> The point you are trying to making, and not doing a great job, is that the compiler cannot create an unknown set of virtual functions from a single templated virtual function. BUT, when you realize that is what the problem is, the unknown set is the issue NOT templated virtual functions. Make the set known and finite somehow then you have a solution, and it's not that difficult. Just requires some elbow grease.
Templates have no idea what arguments you intend to use with them. You can pass them any arguments you want, and as long as they pass the template constraint, the compiler will attempt to instiate the template with those arguments - which may or may not compile, but the compiler doesn't care about that until you attempt to instantiate the template.
The language does not support a mechanism for creating a templated function where you define ahead of time what all of the legal arguments are such that the compiler will just instantiate them all for you. The compiler only instantiates templates when the code instantiates them. Feel free to open up an enhancement request for some sort of template which has a specified list of arguments to be instantiated with which the compiler will then instantiate up front and allow no others, but that is not currently a language feature.
The normal solution for something like that right now would be to explicitly declare each function that you want and then have them call a templated function in order to share the implementation. e.g.
class C
{
public:
auto foo(int i) { return _foo(i); }
auto foo(float f) { return _foo(f); }
auto foo(string s) { return _foo(s); }
private:
auto _foo(T)(T T) { ...}
}
- Jonathan M Davis
|
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Wednesday, 30 August 2017 at 22:08:03 UTC, Jonathan M Davis wrote: > On Wednesday, August 30, 2017 21:51:57 EntangledQuanta via Digitalmars-d- learn wrote: >> The point you are trying to making, and not doing a great job, is that the compiler cannot create an unknown set of virtual functions from a single templated virtual function. BUT, when you realize that is what the problem is, the unknown set is the issue NOT templated virtual functions. Make the set known and finite somehow then you have a solution, and it's not that difficult. Just requires some elbow grease. > > Templates have no idea what arguments you intend to use with them. You can pass them any arguments you want, and as long as they pass the template constraint, the compiler will attempt to instiate the template with those arguments - which may or may not compile, but the compiler doesn't care about that until you attempt to instantiate the template. > > The language does not support a mechanism for creating a templated function where you define ahead of time what all of the legal arguments are such that the compiler will just instantiate them all for you. The compiler only instantiates templates when the code instantiates them. Feel free to open up an enhancement request for some sort of template which has a specified list of arguments to be instantiated with which the compiler will then instantiate up front and allow no others, but that is not currently a language feature. and my point is that it is not always the case that T can be anything. What if T is meant to only be algebraic? auto foo(T : Algebraic!(int, float, double))(T t){ } will the compiler be smart enough to be able to deduce that there are only 3 possibilities? No, but it should. (but of course, we don't want to use algebraic because that makes thing messy, and the whole point of all this is to reduce the mess) As far as a feature request, my guess is no one will care, I'd hope that wouldn't be the case, but seeming how much excitement in solving this problem has generated leads me to believe no one really cares about solving it. > The normal solution for something like that right now would be to explicitly declare each function that you want and then have them call a templated function in order to share the implementation. e.g. > > class C > { > public: > > auto foo(int i) { return _foo(i); } > auto foo(float f) { return _foo(f); } > auto foo(string s) { return _foo(s); } > > private: > > auto _foo(T)(T T) { ...} > } > > - Jonathan M Davis Yes, but this is really just explicit overloading. It doesn't solve the problem that templates are suppose to solve. When one starts overloading things, it becomes a bigger mess as each class needs to deal with the overloading and dispatching. It all could be solved with a bit of compiler "magic"(which should be quite simple). I mean, the compiler optimizes all kinds of things, this case shouldn't be any different. If it can determine a template parameter is reasonably finite then it should convert the templates method in to a series of overloaded methods for us... which is what you essentially did. |
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to EntangledQuanta | On Wednesday, 30 August 2017 at 20:47:12 UTC, EntangledQuanta wrote:
> This is quite surprising!
In the new version pending release (scheduled for later this week), we get a new feature `static foreach` that will let you loop through the types you want and declare all the functions that way.
When it is released, we'll have to take a second look at this problem.
|
August 30, 2017 Re: Bug in D!!! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Wednesday, 30 August 2017 at 22:08:03 UTC, Jonathan M Davis wrote:
> On Wednesday, August 30, 2017 21:51:57 EntangledQuanta via Digitalmars-d- learn wrote:
>> [...]
>
> Templates have no idea what arguments you intend to use with them. You can pass them any arguments you want, and as long as they pass the template constraint, the compiler will attempt to instiate the template with those arguments - which may or may not compile, but the compiler doesn't care about that until you attempt to instantiate the template.
>
> [...]
I'm going to try to implement it as a library solution, something that basically does what you have done. This will at least simplify each instance to a few lines of code but would be required in all derived classes.
|
Copyright © 1999-2021 by the D Language Foundation