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 feed
the 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









Andrey Zherikov <andrey.zherikov gmail.com> 