Re: Getting around the non-virtuality of templates
On 26/03/2012 14:37, Steven Schveighoffer wrote: snip So for now, I use the undocumented old-style functions. One other thing that this wrapper method loses is covariance, which I use a lot in dcollections. I haven't filed a bug on it, but there is at least a workaround on this one -- the template can capture the type of this from the call site as a template parameter. I can't seem to get this to work at the moment: -- class Base { T method(T = typeof(this))() { return this; } } class Derived : Base {} void main() { Base b = new Base; Derived d = new Derived; auto bm = b.method(); auto dm = d.method(); b = d; auto dbm = b.method(); pragma(msg, typeof(bm)); pragma(msg, typeof(dm)); pragma(msg, typeof(dbm)); } -- C:\Users\Stewart\Documents\Programming\D\Testsdmd typeof_this Base Base Base -- Or do you mean something else? snip Set opAnd(E)(bool delegate(E) dg) if(!is(E == Element) implicitlyConvertsTo!(E, Element)) { bool _dg(Element e) { return dg(e); } // call protected virtual opAnd equivalent with _dg } snip I was beginning to think along those lines myself. I'll try it and see how I get on. Stewart.
Re: Getting around the non-virtuality of templates
On 03/27/12 17:12, Stewart Gordon wrote: On 26/03/2012 14:37, Steven Schveighoffer wrote: snip So for now, I use the undocumented old-style functions. One other thing that this wrapper method loses is covariance, which I use a lot in dcollections. I haven't filed a bug on it, but there is at least a workaround on this one -- the template can capture the type of this from the call site as a template parameter. I can't seem to get this to work at the moment: -- class Base { T method(T = typeof(this))() { return this; } } class Base { T method(this T)() { return cast(T)this; } } artur
Re: Getting around the non-virtuality of templates
On 27/03/2012 16:12, Stewart Gordon wrote: On 26/03/2012 14:37, Steven Schveighoffer wrote: snip So for now, I use the undocumented old-style functions. One other thing that this wrapper method loses is covariance, which I use a lot in dcollections. I haven't filed a bug on it, but there is at least a workaround on this one -- the template can capture the type of this from the call site as a template parameter. I can't seem to get this to work at the moment: snip Just figured how to do it. T method(this T)() { return cast(T) this; } Talk about having not got into D2 programming before Stewart.
Re: Getting around the non-virtuality of templates
On Tue, 27 Mar 2012 11:26:08 -0400, Stewart Gordon smjg_1...@yahoo.com wrote: On 27/03/2012 16:12, Stewart Gordon wrote: On 26/03/2012 14:37, Steven Schveighoffer wrote: snip So for now, I use the undocumented old-style functions. One other thing that this wrapper method loses is covariance, which I use a lot in dcollections. I haven't filed a bug on it, but there is at least a workaround on this one -- the template can capture the type of this from the call site as a template parameter. I can't seem to get this to work at the moment: snip Just figured how to do it. T method(this T)() { return cast(T) this; } Talk about having not got into D2 programming before One tip -- if you are doing method as above inside a class and not an interface, you can use: cast(T)cast(void*)this; which should avoid the unnecessary dynamic cast. This will *not* work in an interface. I'd argue the compiler should be aware of the special type of T for doing casts... -Steve
Re: Getting around the non-virtuality of templates
On 27/03/2012 16:46, Steven Schveighoffer wrote: snip One tip -- if you are doing method as above inside a class and not an interface, you can use: cast(T)cast(void*)this; which should avoid the unnecessary dynamic cast. Which would work if the function always returns this. But in the general case of what I'm using it for, it would call a virtual function that is meant to always return an object of the same class as this, but somebody could potentially create a subclass that breaks this rule. But I suppose I could try comparing the .classinfo in an out contract to make sure it doesn't happen This will *not* work in an interface. I'd argue the compiler should be aware of the special type of T for doing casts... What's more, given the this T parameter it ought to automatically treat this as being of type T within the body of the function. Essentially, semantically analyse the function when instantiated as a method of T rather than as a method of the class in which it is actually placed. Stewart.
Re: Getting around the non-virtuality of templates
On Sun, 25 Mar 2012 18:36:08 -0400, Stewart Gordon smjg_1...@yahoo.com wrote: I'm coming up against some interesting challenges while porting stuff in my utility library to D2. Firstly, D2 uses opBinary and opOpAssign, rather than the operator-specific op* and op*Assign. While the latter still work, they aren't mentioned in the current D2 docs. Which would imply that they're on the way out; however, there's no mention at https://github.com/D-Programming-Language/d-programming-language.org/blob/master/deprecate.dd (See also http://d.puremagic.com/issues/show_bug.cgi?id=7779 ) Still, it seems clear that opBinary/opOpAssign is the D2 way of doing it. But it has the drawback that, because it's a template, it isn't virtual. One way about it is to keep the D1-style op functions and make opUnary/opBinary/opOpAssign call these. But is there a better way? I have definitely had issues with this. In dcollections, I have versions of opBinary commented out, because at the time of writing, templates weren't allowed in the D compiler. I filed this bug: http://d.puremagic.com/issues/show_bug.cgi?id=4174 Looks like it hasn't been closed yet... So for now, I use the undocumented old-style functions. One other thing that this wrapper method loses is covariance, which I use a lot in dcollections. I haven't filed a bug on it, but there is at least a workaround on this one -- the template can capture the type of this from the call site as a template parameter. The other isn't a D2-specific issue, though D2 increases the significance of it. I have a method with the signature Set opAnd(bool delegate(Element) dg) I would like to enable a user of the library to pass in a delegate whose parameter is any type to which Element is implicitly convertible. This could be the same type as Element with the top-level constancy changed (probably the main use case), or a type that is distinct beyond the constancy level. Turning it into a template Set opAnd(E)(bool delegate(E) dg) would address this, but prevent overriding with the appropriate code for each set implementation. What I would do is this (assuming template interfaces worked): Set opAnd(E)(bool delegate(E) dg) if(is(E == Element)) { // call protected virtual opAnd equivalent which takes delegate of Element } Set opAnd(E)(bool delegate(E) dg) if(!is(E == Element) implicitlyConvertsTo!(E, Element)) { bool _dg(Element e) { return dg(e); } // call protected virtual opAnd equivalent with _dg } Note, with proper delegate implicit conversions, you could probably get some better optimization (including delegates that only differ by const) by checking if the delegate implicitly converts instead of the element. -Steve
Getting around the non-virtuality of templates
I'm coming up against some interesting challenges while porting stuff in my utility library to D2. Firstly, D2 uses opBinary and opOpAssign, rather than the operator-specific op* and op*Assign. While the latter still work, they aren't mentioned in the current D2 docs. Which would imply that they're on the way out; however, there's no mention at https://github.com/D-Programming-Language/d-programming-language.org/blob/master/deprecate.dd (See also http://d.puremagic.com/issues/show_bug.cgi?id=7779 ) Still, it seems clear that opBinary/opOpAssign is the D2 way of doing it. But it has the drawback that, because it's a template, it isn't virtual. One way about it is to keep the D1-style op functions and make opUnary/opBinary/opOpAssign call these. But is there a better way? The other isn't a D2-specific issue, though D2 increases the significance of it. I have a method with the signature Set opAnd(bool delegate(Element) dg) I would like to enable a user of the library to pass in a delegate whose parameter is any type to which Element is implicitly convertible. This could be the same type as Element with the top-level constancy changed (probably the main use case), or a type that is distinct beyond the constancy level. Turning it into a template Set opAnd(E)(bool delegate(E) dg) would address this, but prevent overriding with the appropriate code for each set implementation. Who else has been faced with this problem? Have you found a good way of dealing with it? Stewart.
Re: Getting around the non-virtuality of templates
On 26 March 2012 11:36, Stewart Gordon smjg_1...@yahoo.com wrote: I'm coming up against some interesting challenges while porting stuff in my utility library to D2. Firstly, D2 uses opBinary and opOpAssign, rather than the operator-specific op* and op*Assign. While the latter still work, they aren't mentioned in the current D2 docs. Which would imply that they're on the way out; however, there's no mention at https://github.com/D-Programming-Language/d-programming-language.org/blob/master/deprecate.dd (See also http://d.puremagic.com/issues/show_bug.cgi?id=7779 ) Still, it seems clear that opBinary/opOpAssign is the D2 way of doing it. But it has the drawback that, because it's a template, it isn't virtual. One way about it is to keep the D1-style op functions and make opUnary/opBinary/opOpAssign call these. But is there a better way? The other isn't a D2-specific issue, though D2 increases the significance of it. I have a method with the signature Set opAnd(bool delegate(Element) dg) I would like to enable a user of the library to pass in a delegate whose parameter is any type to which Element is implicitly convertible. This could be the same type as Element with the top-level constancy changed (probably the main use case), or a type that is distinct beyond the constancy level. Turning it into a template Set opAnd(E)(bool delegate(E) dg) would address this, but prevent overriding with the appropriate code for each set implementation. Who else has been faced with this problem? Have you found a good way of dealing with it? Stewart. Non-virtuality of templates is a general problem at the moment. The issues seem to be around how to handle inheritance of template arguments, and how to dispatch the functions based on a combination of template arguments and class hierarchy. This is a hard problem with no obvious answer. in terms of trying to work around it, perhaps compile-time reflection could help, I haven't encountered this before, but that's where I would start. -- James Miller
Re: Getting around the non-virtuality of templates
On Mon, 26 Mar 2012 00:36:08 +0200, Stewart Gordon smjg_1...@yahoo.com wrote: I'm coming up against some interesting challenges while porting stuff in my utility library to D2. Firstly, D2 uses opBinary and opOpAssign, rather than the operator-specific op* and op*Assign. While the latter still work, they aren't mentioned in the current D2 docs. Which would imply that they're on the way out; however, there's no mention at https://github.com/D-Programming-Language/d-programming-language.org/blob/master/deprecate.dd (See also http://d.puremagic.com/issues/show_bug.cgi?id=7779 ) Still, it seems clear that opBinary/opOpAssign is the D2 way of doing it. But it has the drawback that, because it's a template, it isn't virtual. One way about it is to keep the D1-style op functions and make opUnary/opBinary/opOpAssign call these. But is there a better way? The other isn't a D2-specific issue, though D2 increases the significance of it. I have a method with the signature Set opAnd(bool delegate(Element) dg) I would like to enable a user of the library to pass in a delegate whose parameter is any type to which Element is implicitly convertible. This could be the same type as Element with the top-level constancy changed (probably the main use case), or a type that is distinct beyond the constancy level. Turning it into a template Set opAnd(E)(bool delegate(E) dg) would address this, but prevent overriding with the appropriate code for each set implementation. Who else has been faced with this problem? Have you found a good way of dealing with it? Stewart. I believe the officially vetted answer is to have the templated calls forward to virtual functions. Of course, if you need to do something specific before handing it there, you're out of luck.