From 838a8f21837f228003acb257c24e059250fd00e2 Mon Sep 17 00:00:00 2001
From: gcxfd
Date: Wed, 23 Feb 2022 01:09:54 +0800
Subject: [PATCH] docs: improve the documentation for struct embedding (#13560)
---
doc/docs.md | 123 ++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 95 insertions(+), 28 deletions(-)
diff --git a/doc/docs.md b/doc/docs.md
index 4939f27000..35267747fd 100644
--- a/doc/docs.md
+++ b/doc/docs.md
@@ -87,11 +87,11 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
* [Match](#match)
* [Defer](#defer)
* [Structs](#structs)
- * [Embedded structs](#embedded-structs)
* [Default field values](#default-field-values)
* [Short struct literal syntax](#short-struct-literal-syntax)
* [Access modifiers](#access-modifiers)
* [Methods](#methods)
+ * [Embedded structs](#embedded-structs)
* [Unions](#unions)
@@ -1929,33 +1929,6 @@ println(p.x)
The type of `p` is `&Point`. It's a [reference](#references) to `Point`.
References are similar to Go pointers and C++ references.
-### Embedded structs
-
-V doesn't allow subclassing, but it supports embedded structs:
-
-```v
-struct Widget {
-mut:
- x int
- y int
-}
-
-struct Button {
- Widget
- title string
-}
-
-mut button := Button{
- title: 'Click me'
-}
-button.x = 3
-```
-Without embedding we'd have to name the `Widget` field and do:
-
-```v oksyntax
-button.widget.x = 3
-```
-
### Default field values
```v
@@ -2139,6 +2112,100 @@ In this example, the `can_register` method has a receiver of type `User` named `
The convention is not to use receiver names like `self` or `this`,
but a short, preferably one letter long, name.
+### Embedded structs
+
+V support embedded structs .
+
+```v
+struct Size {
+mut:
+ width int
+ height int
+}
+
+fn (s &Size) area() int {
+ return s.width * s.height
+}
+
+struct Button {
+ Size
+ title string
+}
+```
+
+With embedding, the struct `Button` will automatically have get all the fields and methods from
+the struct `Size`, which allows you to do:
+
+```v oksyntax
+mut button := Button{
+ title: 'Click me'
+ height: 2
+}
+
+button.width = 3
+assert button.area() == 6
+assert button.Size.area() == 6
+print(button)
+```
+
+output :
+```
+Button{
+ Size: Size{
+ width: 3
+ height: 2
+ }
+ title: 'Click me'
+}
+```
+
+Slightly similar to inheritance, a struct will automatically get all the fields and methods
+from its embedded structs.
+
+Unlike inheritance however, you cannot type cast between structs and embedded structs
+(the embedding struct can also has its own fields, and it can also embed multiple structs).
+
+If you need to access embedded structs directly, use an explicit reference like `button.Size`.
+
+Conceptually, embedded structs are similar to [mixin](https://en.wikipedia.org/wiki/Mixin)s
+in OOP, *NOT* base classes.
+
+An embedded structs is responsible for implementing a common structure and exposing a few
+functions, just like Lego blocks.
+
+It is not recommended to create a bulky base class with a huge number of fields or functions.
+There is no need to import a forest for a banana.
+
+> The problem with object-oriented languages is they’ve got all this implicit environment
+> that they carry around with them. You wanted a banana but what you got was a gorilla
+> holding the banana and the entire jungle.
+
+—— Joe Armstrong, creator of Erlang progamming language
+
+If multiple embedded structs have methods or fields with the same name, or if methods or fields
+with the same name are defined in the struct, you can call functions or assign to variables in
+the embedded struct like `button.Size.area()`.
+
+You can also initialize an embedded struct:
+
+```v oksyntax
+mut button := Button{
+ Size: Size{
+ width: 3
+ height: 2
+ }
+}
+```
+
+or assign values:
+
+```v oksyntax
+button.Size = Size{
+ width: 4
+ height: 5
+}
+```
+
## Unions
Just like structs, unions support embedding.
|