Re: Covariant callback functions, or assigning base class members through a subclass reference
On 2015-07-14 17:53, Rene Zwanenburg wrote: Sure, but that would make Base!Derived and Base!AnotherSubClass different types. What I'd like to end up with is a Base[], being able to call foo() on the array members. Other parts of the code will add instances of derived types to this array, and have set the callback function to a delegate accepting said derived type. You can add another base type that is not templated: abstract class Base { abstract void foo (); } abstract class TemplateBase(T) : Base { alias CallbackType = void delegate(T); CallbackType callback; override void foo () { callback(cast(T) this); } } class Derived : TemplateBase!(Derived) { void derivedFunc() { import std.stdio; writeln("Derived object in action..."); } } void main() { auto d = new Derived(); d.callback = (Derived d) { d.derivedFunc(); }; Base[] bases = [d]; foreach (b ; bases) b.foo(); } -- /Jacob Carlborg
Re: Covariant callback functions, or assigning base class members through a subclass reference
On 07/14/2015 08:28 AM, Rene Zwanenburg wrote: > But the CallbackType should be able to prevent such unsafe assignments. The following struct applies what others have recommended only if an actual derived type is provided. However, it is still unsafe as the direct assignment to 'callback' cannot know that the object is the same as template parameter D. struct CallbackBased(B) { alias Func = void delegate(B); Func func; void opAssign(D)(void delegate(D) arg) if (is (D : B)) { func = cast(Func)(arg); } void opCall(B obj) { func(obj); } } class Base { alias CallbackType = CallbackBased!Base; CallbackType callback; void foo() { callback(this); } } class Derived : Base { void derivedFunc() { import std.stdio; writeln("Derived object in action..."); } } void main() { auto d = new Derived(); d.callback = (Derived d) { d.derivedFunc(); }; d.foo(); } Ali
Re: Covariant callback functions, or assigning base class members through a subclass reference
On 2015-07-14 17:28, Rene Zwanenburg wrote: Given the following code: class Base { alias CallbackType = void delegate(Base); CallbackType callback; void foo() { callback(this); } } class Derived : Base { } void main() { auto d = new Derived(); d.callback = (Derived d) { /* Do something */ } } Obviously this won't compile, since the callback function needs to have Base as parameter, not Derived. You can cast the delegate. It's probably unsafe but a simple example works. -- /Jacob Carlborg
Re: Covariant callback functions, or assigning base class members through a subclass reference
On Tuesday, 14 July 2015 at 17:26:32 UTC, Steven Schveighoffer wrote: On 7/14/15 11:28 AM, Rene Zwanenburg wrote: Given the following code: class Base { alias CallbackType = void delegate(Base); CallbackType callback; void foo() { callback(this); } } class Derived : Base { } void main() { auto d = new Derived(); d.callback = (Derived d) { /* Do something */ } } Obviously this won't compile, since the callback function needs to have Base as parameter, not Derived. But the given code is perfectly safe because in main d typed as Derived, not Base. Does anyone know a clean way to support the code given in main(), preferably by defining some smart CallbackType so Derived doesn't need to be modified? No, this isn't possible. Only thing you can do is: d.callback = (Base b) { if(auto d = cast(Derived)b) { /* Do something */ } else assert(0); }; -Steve Thanks, I'll have to think of something else then. At my day job I mostly work with C#, and I strongly dislike how event handler parameters there have to be broader-typed (is that even a valid term?) than they logically need to be, which is why I'm trying to avoid doing something similar here.
Re: Covariant callback functions, or assigning base class members through a subclass reference
On 7/14/15 11:28 AM, Rene Zwanenburg wrote: Given the following code: class Base { alias CallbackType = void delegate(Base); CallbackType callback; void foo() { callback(this); } } class Derived : Base { } void main() { auto d = new Derived(); d.callback = (Derived d) { /* Do something */ } } Obviously this won't compile, since the callback function needs to have Base as parameter, not Derived. But the given code is perfectly safe because in main d typed as Derived, not Base. Does anyone know a clean way to support the code given in main(), preferably by defining some smart CallbackType so Derived doesn't need to be modified? No, this isn't possible. Only thing you can do is: d.callback = (Base b) { if(auto d = cast(Derived)b) { /* Do something */ } else assert(0); }; -Steve
Re: Covariant callback functions, or assigning base class members through a subclass reference
On Tuesday, 14 July 2015 at 15:35:04 UTC, Kagamin wrote: Template Base on Derived: class Derived : Base!Derived { } Sure, but that would make Base!Derived and Base!AnotherSubClass different types. What I'd like to end up with is a Base[], being able to call foo() on the array members. Other parts of the code will add instances of derived types to this array, and have set the callback function to a delegate accepting said derived type. This is part of a library I'm working on. I don't mind if the library itself contains some nastiness to get this to work, as long as user code, which defines the derived types, is type safe and clean.
Re: Covariant callback functions, or assigning base class members through a subclass reference
Template Base on Derived: class Derived : Base!Derived { }
Covariant callback functions, or assigning base class members through a subclass reference
Given the following code: class Base { alias CallbackType = void delegate(Base); CallbackType callback; void foo() { callback(this); } } class Derived : Base { } void main() { auto d = new Derived(); d.callback = (Derived d) { /* Do something */ } } Obviously this won't compile, since the callback function needs to have Base as parameter, not Derived. But the given code is perfectly safe because in main d typed as Derived, not Base. Does anyone know a clean way to support the code given in main(), preferably by defining some smart CallbackType so Derived doesn't need to be modified? I understand this is unsafe in other scenarios, for example: class AnotherSubClass : Base { } void bar(Base b1, Base b2) { b1.callback = b2.callback; } void doom() { auto b1 = new Derived(); auto b2 = new AnotherSubClass(); b2.callback = (AnotherSubClass a) { }; bar(b1, b2); } But the CallbackType should be able to prevent such unsafe assignments.