digitalmars.D.learn - Templatized delegates
- Andrey Zherikov (44/44) May 31 2022 I have tightly coupled code which I'd like to decouple but I'm a
- Paul Backus (42/53) May 31 2022 If you want compile-time polymorphism, three's no other way. If
- Andrey Zherikov (5/43) May 31 2022 Unfortunately this solution looses important feature: there is no
- Andrey Zherikov (32/35) May 31 2022 In case if `S.doSomething` is NOT template function then the
- =?UTF-8?Q?Christian_K=c3=b6stlin?= (3/55) May 31 2022 the delegate into it (and create the delegate outside). This would also
- Andrey Zherikov (2/7) May 31 2022 That's possible but the problem is that `S` is part of `DG`.
I have tightly coupled code which I'd like to decouple but I'm a bit stuck. For simplicity, I reduced the amount of code to something simple to understand. So I have a struct `S` that has templated member function that does something. On the other side I have delegate holder `R` - this delegate takes `S` object as an argument and calls that function. My goal is to remove dependency from `R` to `S`. Here is code example: ```d import std.stdio: writeln; struct S { // function that should be called from delegate void doSomething(T)(T value) { value.writeln; } } alias DG = void delegate (ref S s); auto createDG(T)(T value) { return delegate (ref S s) { s.doSomething(value); }; } struct R { DG dg; this(int value) { dg = createDG(value); } } void main() { auto r = R(5); S s; r.dg(s); } ``` An obvious way is to add a type template parameter to `R`, `DG` and `createDG` but I would like to avoid this. Is there another way to do so? I think ideal solution would be having templatized delegate `void delegate (S)(ref S s)` and then call `r.dg!S(s)` but it's not available: `alias DG = void delegate (S) (ref S s)` gives unclear `Error: function declaration without return type. (Note that constructors are always named 'this')` message.
May 31 2022
On Tuesday, 31 May 2022 at 21:15:24 UTC, Andrey Zherikov wrote:I have tightly coupled code which I'd like to decouple but I'm a bit stuck. For simplicity, I reduced the amount of code to something simple to understand. So I have a struct `S` that has templated member function that does something. On the other side I have delegate holder `R` - this delegate takes `S` object as an argument and calls that function. My goal is to remove dependency from `R` to `S`.[...]An obvious way is to add a type template parameter to `R`, `DG` and `createDG` but I would like to avoid this. Is there another way to do so?If you want compile-time polymorphism, three's no other way. If you're ok with runtime polymorphism, you could replace S with something like an interface or a sum type. For example: ```d import std.stdio; struct S { // function that should be called from delegate void doSomething(T)(T value) { value.writeln; } } interface I { void doSomething(int value); } class Adapter : I { S s; this(S s) { this.s = s; } void doSomething(int value) { s.doSomething(value); } } alias DG = void delegate (I i); auto createDG(int value) { return delegate (I i) { i.doSomething(value); }; } struct R { DG dg; this(int value) { dg = createDG(value); } } void main() { auto r = R(5); S s; r.dg(new Adapter(s)); } ```
May 31 2022
On Tuesday, 31 May 2022 at 21:53:17 UTC, Paul Backus wrote:If you want compile-time polymorphism, three's no other way.Yes, I want compile-time polymorphism.```d import std.stdio; struct S { // function that should be called from delegate void doSomething(T)(T value) { value.writeln; } } interface I { void doSomething(int value); } class Adapter : I { S s; this(S s) { this.s = s; } void doSomething(int value) { s.doSomething(value); } } alias DG = void delegate (I i); auto createDG(int value) { return delegate (I i) { i.doSomething(value); }; } struct R { DG dg; this(int value) { dg = createDG(value); } } void main() { auto r = R(5); S s; r.dg(new Adapter(s)); } ```Unfortunately this solution looses important feature: there is no more templated call to `S.doSomething` as `I.doSomething` is not template and adding override for every type is not maintainable.
May 31 2022
On Tuesday, 31 May 2022 at 23:15:24 UTC, Andrey Zherikov wrote:On Tuesday, 31 May 2022 at 21:53:17 UTC, Paul Backus wrote:In case if `S.doSomething` is NOT template function then the problem can be solved easily by wrapping access to `S` into another delegate: ```d import std.stdio: writeln; struct S { void doSomething(int value) { value.writeln; } } alias DG = void delegate (void delegate(int) doSomething); auto createDG(T)(T value) { return delegate (void delegate(int) doSomething) { doSomething(value); }; } struct R { DG dg; this(int value) { dg = createDG(value); } } void main() { auto r = R(5); S s; r.dg(_ => s.doSomething(_)); } ``` How to do the same for templated `S.doSomething`?If you want compile-time polymorphism, three's no other way.Yes, I want compile-time polymorphism.
May 31 2022
On 2022-05-31 23:15, Andrey Zherikov wrote:I have tightly coupled code which I'd like to decouple but I'm a bit stuck. For simplicity, I reduced the amount of code to something simple to understand. So I have a struct `S` that has templated member function that does something. On the other side I have delegate holder `R` - this delegate takes `S` object as an argument and calls that function. My goal is to remove dependency from `R` to `S`. Here is code example: ```d import std.stdio: writeln; struct S { // function that should be called from delegate void doSomething(T)(T value) { value.writeln; } } alias DG = void delegate (ref S s); auto createDG(T)(T value) { return delegate (ref S s) { s.doSomething(value); }; } struct R { DG dg; this(int value) { dg = createDG(value); } } void main() { auto r = R(5); S s; r.dg(s); } ``` An obvious way is to add a type template parameter to `R`, `DG` and `createDG` but I would like to avoid this. Is there another way to do so? I think ideal solution would be having templatized delegate `void delegate (S)(ref S s)` and then call `r.dg!S(s)` but it's not available: `alias DG = void delegate (S) (ref S s)` gives unclear `Error: function declaration without return type. (Note that constructors are always named 'this')` message.Would it help to not create the delegate in R's constructor, but feedthe delegate into it (and create the delegate outside). This would also resemble your description (R is a delegate holder) more.
May 31 2022
On Tuesday, 31 May 2022 at 22:34:41 UTC, Christian Köstlin wrote:Would it help to not create the delegate in R's constructor, but feed the delegate into it (and create the delegate outside). This would also resemble your description (R is a delegate holder) more.That's possible but the problem is that `S` is part of `DG`.
May 31 2022