www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Virtual methods on stack objects

reply Marvin Hannott <i28muzw0n relay.firefox.com> writes:
Hi everybody!

I understand that D's classes solve some particular problems. 
However, they also cause problems because they cannot be copied 
when scoped. So how do I get virtual methods on a copyable stack 
object?
May 11 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/11/22 06:57, Marvin Hannott wrote:

 I understand that D's classes solve some particular problems. However,
 they also cause problems because they cannot be copied when scoped. So
 how do I get virtual methods on a copyable stack object?
Problems classes solve don't usually need copying nor need to be on the stack. Is that really necessary? If so, I can think of two solutions: a) Use a struct but provide "virtual" functions manually (with function pointers like one would do in C, all of which potentially collected in a per-type function table (a.k.a. vtbl :) )). b) Use classes but provide a virtual function that you call to copy. Ali
May 11 2022
parent reply Marvin Hannott <i28muzw0n relay.firefox.com> writes:
On Wednesday, 11 May 2022 at 14:44:59 UTC, Ali Çehreli wrote:
 On 5/11/22 06:57, Marvin Hannott wrote:

 I understand that D's classes solve some particular problems.
However,
 they also cause problems because they cannot be copied when
scoped. So
 how do I get virtual methods on a copyable stack object?
Problems classes solve don't usually need copying nor need to be on the stack. Is that really necessary? If so, I can think of two solutions: a) Use a struct but provide "virtual" functions manually (with function pointers like one would do in C, all of which potentially collected in a per-type function table (a.k.a. vtbl :) )). b) Use classes but provide a virtual function that you call to copy. Ali
I appreciate the answer, don't much like the "solutions". It's not so much about copying, but about heap allocations. Tying virtual methods to heap allocation is kind of unfortunate. And I am not really keen on building a poor man's vtbl. And for my taste, scoped class objects should have value semantics.
May 11 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/11/22 13:06, Marvin Hannott wrote:

 I appreciate the answer, don't much like the "solutions".
Me neither. :)
 It's not so much about copying
Great!
 scoped class objects should have value semantics.
std.typecons.scoped does exactly that: https://dlang.org/phobos/std_typecons.html#scoped import std.stdio; import std.typecons; interface Animal { string sing(); } class Cat : Animal { this() { writeln("Hi!"); } ~this() { writeln("Bye!"); } string sing() { return "mew"; } } void foo(Animal animal) { writeln(animal.sing()); } void bar() { auto cat = scoped!Cat(); foo(cat); } void main() { bar(); } The output: Hi! mew Bye! Ali
May 11 2022
parent reply Marvin Hannott <i28muzw0n relay.firefox.com> writes:
On Wednesday, 11 May 2022 at 20:23:07 UTC, Ali Çehreli wrote:
 On 5/11/22 13:06, Marvin Hannott wrote:

 I appreciate the answer, don't much like the "solutions".
Me neither. :)
 It's not so much about copying
Great!
 scoped class objects should have value semantics.
std.typecons.scoped does exactly that: https://dlang.org/phobos/std_typecons.html#scoped import std.stdio; import std.typecons; interface Animal { string sing(); } class Cat : Animal { this() { writeln("Hi!"); } ~this() { writeln("Bye!"); } string sing() { return "mew"; } } void foo(Animal animal) { writeln(animal.sing()); } void bar() { auto cat = scoped!Cat(); foo(cat); } void main() { bar(); } The output: Hi! mew Bye! Ali
Yeah, but you can't return `Cat` 😉. And the documentation for `scoped` says:
It's illegal to move a class instance even if you are sure there 
are no pointers to it. As such, it is illegal to move a scoped 
object.
That's kinda very limiting. Anyway, I cooked up another idea based on your first suggestions. ```D struct S { static private interface I { int f(int i); } static private final class A : I { int f(int i) {return i;} } static private final class B : I { int f(int i) {return i+ 1;} } private I i; private int d; this(int d) { this.d = d; if(d < 10) { i = scoped!A(); }else { i = scoped!B(); } } int f() { return i.f(d);} } ``` I mean, this is a super dumb example, but it kinda works. And I think it could be made a lot less tedious with some mixin magic.
May 11 2022
next sibling parent dangbinghoo <dangbinghoo gmail.com> writes:
On Wednesday, 11 May 2022 at 20:53:21 UTC, Marvin Hannott wrote:
 On Wednesday, 11 May 2022 at 20:23:07 UTC, Ali Çehreli wrote:
 [...]
Yeah, but you can't return `Cat` 😉. And the documentation for `scoped` says:
[...]
That's kinda very limiting. Anyway, I cooked up another idea based on your first suggestions. ```D struct S { static private interface I { int f(int i); } static private final class A : I { int f(int i) {return i;} } static private final class B : I { int f(int i) {return i+ 1;} } private I i; private int d; this(int d) { this.d = d; if(d < 10) { i = scoped!A(); }else { i = scoped!B(); } } int f() { return i.f(d);} } ``` I mean, this is a super dumb example, but it kinda works. And I think it could be made a lot less tedious with some mixin magic.
add a single `writeln("A.f")` to A.f and `writeln("B.f")` B.f, and a simple test ```d void main() { S s1 = S(9); S s2 = S(12); s1.f(); s2.f(); } ``` outputs: ``` A.f Error: program killed by signal 11 (Aka. segmentation fault !) ```
May 11 2022
prev sibling parent vit <vit vit.vit> writes:
On Wednesday, 11 May 2022 at 20:53:21 UTC, Marvin Hannott wrote:
 On Wednesday, 11 May 2022 at 20:23:07 UTC, Ali Çehreli wrote:
 On 5/11/22 13:06, Marvin Hannott wrote:

 I appreciate the answer, don't much like the "solutions".
Me neither. :)
 It's not so much about copying
Great!
 scoped class objects should have value semantics.
std.typecons.scoped does exactly that: https://dlang.org/phobos/std_typecons.html#scoped import std.stdio; import std.typecons; interface Animal { string sing(); } class Cat : Animal { this() { writeln("Hi!"); } ~this() { writeln("Bye!"); } string sing() { return "mew"; } } void foo(Animal animal) { writeln(animal.sing()); } void bar() { auto cat = scoped!Cat(); foo(cat); } void main() { bar(); } The output: Hi! mew Bye! Ali
Yeah, but you can't return `Cat` 😉. And the documentation for `scoped` says:
It's illegal to move a class instance even if you are sure 
there are no pointers to it. As such, it is illegal to move a 
scoped object.
That's kinda very limiting. Anyway, I cooked up another idea based on your first suggestions. ```D struct S { static private interface I { int f(int i); } static private final class A : I { int f(int i) {return i;} } static private final class B : I { int f(int i) {return i+ 1;} } private I i; private int d; this(int d) { this.d = d; if(d < 10) { i = scoped!A(); }else { i = scoped!B(); } } int f() { return i.f(d);} } ``` I mean, this is a super dumb example, but it kinda works. And I think it could be made a lot less tedious with some mixin magic.
`scoped` is not necesary, try this: ```d import std.typecons; struct S{ static private interface I{ int f(int i)const; } static private final class A : I{ static immutable typeof(this) instance = new immutable typeof(this)(); int f(int i)const {return i;} } static private final class B : I{ static immutable typeof(this) instance = new immutable typeof(this)(); int f(int i)const {return i+ 1;} } private immutable I i; private int d; this(int d){ this.d = d; if(d < 10) i = A.instance; else i = B.instance; } int f() { return i.f(d);} } void main(){ import std.stdio; S(1).f().writeln(); /// 1 S(100).f().writeln(); /// 101 } ```
May 12 2022