digitalmars.D.learn - What are virtual functions?
- Berni44 (16/16) Apr 14 2021 I'm trying to understand, what virtual functions are. I found the
- Paul Backus (6/9) Apr 14 2021 The recommended `toString` versions are templates, but virtual
- FeepingCreature (40/52) Apr 14 2021 Recommended reading:
- ShadoLight (22/25) Apr 18 2021 [..]
- Alain De Vos (2/2) Apr 18 2021 Also three words are used in this context.
- FeepingCreature (17/44) Apr 18 2021 ... That doesn't work?! Holy hell. I mean, run.dlang.io confirms,
I'm trying to understand, what virtual functions are. I found the [specs](https://dlang.org/spec/function.html#virtual-functions), but I can't make head or tail of it. - What is a `vtbl[]`? Obviously a function pointer table. But where to find this? The examples don't use it. Maybe something inside of the compiler? - Which of the eight functions in the example are virtual and and which not? OK B.abc is said to be virtual, as the comment states. But it seems never to be used. And why is it considered to be virtual? - There is also the term "covariant function", which is not explained. What is this? I'm asking, because I'm currently writing new docs for `std.format`. The [current (stable) docs of `formatValue`](https://dlang.org/phobos/std_format.html#formatValue) tell, that some `toString` versions are discouraged, but not for virtual functions. I would like to understand the reason for that, so I can put that properly into the new docs. The reasons, why it's better to not use these versions in normal functions is explained in the [changelog](https://dlang.org/changelog/2.079.0.html#toString). But I miss the reason, why virtual functions should still use them; probably, because I did not understand, what that is. Can you help me?
Apr 14 2021
On Wednesday, 14 April 2021 at 13:43:20 UTC, Berni44 wrote:I'm asking, because I'm currently writing new docs for `std.format`. The [current (stable) docs of `formatValue`](https://dlang.org/phobos/std_format.html#formatValue) tell, that some `toString` versions are discouraged, but not for virtual functions. I would like to understand the reason for that, so I can put that properly into the new docs. The reasons, why it's better to not use these versions in normal functions is explained in the [changelog](https://dlang.org/changelog/2.079.0.html#toString). But I miss the reason, why virtual functions should still use them; probably, because I did not understand, what that is.The recommended `toString` versions are templates, but virtual functions can't be templates (because you can't have a function pointer that points to a template). So, the non-template versions are still considered acceptable for cases when `toString` has to be virtual--i.e., when you're overriding `Object.toString`.
Apr 14 2021
On Wednesday, 14 April 2021 at 13:43:20 UTC, Berni44 wrote:I'm trying to understand, what virtual functions are. I found the [specs](https://dlang.org/spec/function.html#virtual-functions), but I can't make head or tail of it. - What is a `vtbl[]`? Obviously a function pointer table. But where to find this? The examples don't use it. Maybe something inside of the compiler? - Which of the eight functions in the example are virtual and and which not? OK B.abc is said to be virtual, as the comment states. But it seems never to be used. And why is it considered to be virtual? - There is also the term "covariant function", which is not explained. What is this?Recommended reading: https://en.wikipedia.org/wiki/Liskov_substitution_principle This is all related to object-oriented programming and class inheritance. Because we can put a subclass object into a superclass variable (`class Child : Parent { }; Parent parent = new Child;`), we cannot look at the *type* of an object variable to decide which methods to call, because the object itself may be of a subtype. As such, when we call a method `foo` on `Parent`, the compiler looks up the class info in a pointer in the first 8 bytes of the object, finds the method pointer for `foo`, and calls it with the object as a hidden parameter. (This is the `this` field.) So a virtual method is a method that is called "virtually", as compared to directly by name, by turning the method name into a function pointer call via the classinfo. The list of function pointers for methods in the class info is called the virtual method table, or vtable. Covariance is related to the Liskov principle, and just means that because `Child` can be treated as a `Parent`, a method that returns `Parent` in the superclass can be overridden (its vtable pointer replaced with a new one) by one that returns a `Child` in the subclass. In other words, as "Child class replaces Parent class", the "return type `Child`" can replace the "return type `Parent`"; ie. in the child class you can use a child class of the return type, ie. they "vary together" - covariance. The opposite (contravariance) happens for parameters: if a superclass method takes `Child`, the subclass can take `Parent` instead - again, because `Child` can turn into `Parent` per Liskov. A different way to think about this is that method parameter and return types form a contract that is defined by the superclass and fulfilled by the subclass, and the subclass can relax the call contract ("I demand from my caller") and restrict the return contract ("I promise my caller"). Since the `Child`, by Liskov, can do everything the `Parent` can do, demanding less - ie. a `Parent` instead of a `Child` - keeps the superclass's call contract valid, and promising more - ie. returning a `Child` instead of a `Parent`, which may have additional capabilities - keeps the superclass's return contract valid.
Apr 14 2021
On Wednesday, 14 April 2021 at 14:06:18 UTC, FeepingCreature wrote:On Wednesday, 14 April 2021 at 13:43:20 UTC, Berni44 wrote:[..]Covariance is related ...[..]The opposite (contravariance) happens ...[..]Nice answer but, just to be clear - D only supports covariance on return types at the moment, and doesn't support contravariance on parameters, right? I remember contravariance being periodically requested in the past but, AFAICR, it has not been implemented, right? A quick search through the forums didn't turn anything up either... and this does not compile: ``` class A {} class B : A {} class Y { public void bar (B b) {} } class X : Y { public override void bar (A a){} } ```
Apr 18 2021
Also three words are used in this context. Static binding, dynamic binding, late binding.
Apr 18 2021
On Sunday, 18 April 2021 at 23:04:26 UTC, ShadoLight wrote:On Wednesday, 14 April 2021 at 14:06:18 UTC, FeepingCreature wrote:... That doesn't work?! Holy hell. I mean, run.dlang.io confirms, but ... *why not*?! If you already support return type covariance, parameter contravariance should be easy. It's the same thing! You don't need to do anything! Any B is directly a valid A! Like, sure, there's versions of this that don't trivially work, like mixing interface and class parents, but direct superclass contravariance should be easy. ... Weird. I don't get it. Reading https://issues.dlang.org/show_bug.cgi?id=3075 seems like it collides with overloading. Except ... it doesn't. Because you can't implement multiple overloaded methods with contravariance in a subclass, because it doesn't work for interfaces anyway (cause they occupy a different interface slot in the class and so aren't strictly Liskov.) So the selection of the function to override is still unambiguous. I don't get it.On Wednesday, 14 April 2021 at 13:43:20 UTC, Berni44 wrote:[..]Covariance is related ...[..]The opposite (contravariance) happens ...[..]Nice answer but, just to be clear - D only supports covariance on return types at the moment, and doesn't support contravariance on parameters, right? I remember contravariance being periodically requested in the past but, AFAICR, it has not been implemented, right? A quick search through the forums didn't turn anything up either... and this does not compile: ``` class A {} class B : A {} class Y { public void bar (B b) {} } class X : Y { public override void bar (A a){} } ```
Apr 18 2021