www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What are virtual functions?

reply Berni44 <someone somemail.com> writes:
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
next sibling parent Paul Backus <snarwin gmail.com> writes:
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
prev sibling parent reply FeepingCreature <feepingcreature gmail.com> writes:
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
parent reply ShadoLight <ettienne.gilbert gmail.com> writes:
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
next sibling parent Alain De Vos <devosalain ymail.com> writes:
Also three words are used in this context.
Static binding, dynamic binding, late binding.
Apr 18 2021
prev sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Sunday, 18 April 2021 at 23:04:26 UTC, ShadoLight wrote:
 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){}
 }
 ```
... 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.
Apr 18 2021