WWW-www.enlightenment.org pushed a commit to branch master.

http://git.enlightenment.org/website/www-content.git/commit/?id=ced687f6c3a3cafc22ab26934dd0f24bea6654cc

commit ced687f6c3a3cafc22ab26934dd0f24bea6654cc
Author: Xavi Artigas <[email protected]>
Date:   Mon Nov 20 04:38:02 2017 -0800

    Wiki page eo-inherit.md changed with summary [created] by Xavi Artigas
---
 pages/develop/tutorial/c/eo-inherit.md.txt | 280 +++++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)

diff --git a/pages/develop/tutorial/c/eo-inherit.md.txt 
b/pages/develop/tutorial/c/eo-inherit.md.txt
new file mode 100644
index 00000000..ae5f243f
--- /dev/null
+++ b/pages/develop/tutorial/c/eo-inherit.md.txt
@@ -0,0 +1,280 @@
+---
+~~Title: Class Inheritance with Eolian~~
+---
+
+# Class Inheritance with Eolian #
+
+The [Creating New Classes](eo-classes.md) tutorial explained how to define new 
classes using Eolian. New classes, though, don't need to start from scratch. In 
fact, it is common practice in *Object Oriented Programming* to (OOP) extend 
the functionality of an existing class by *inheriting* from it and creating a 
new one.
+
+This tutorial shows how to inherit from a class in Eolian. It also describes 
*interfaces*, a particular kind of class which allows describing common 
functionality across different classes.
+
+## Prerequisites ##
+
+* This tutorial builds on top of the ``Example.Rectangle`` class developed in 
[Creating New Classes with Eolian](eo-classes.md).
+* The [Hello World](hello-world.md) tutorial explains how to write an 
application using the EFL.
+
+## Step One: Creating a Derived Class ##
+
+Copy all the ``example_rectangle.*`` files you created in the [Creating New 
Classes with Eolian](eo-classes.md) tutorial. There should be 4 of them: The 
Eolian file (``.eo``), the implementation file (``.c``) and two autogenerated 
files (``.eo.h`` and ``.eo.c``). Also copy the main file 
(``eo_classes_main.c``) and rename it to ``eo_inherit_main.c``, for consistency 
with the name of this tutorial.
+
+Now you will create a new class, named ``Example.Square`` which will inherit 
from ``Example.rectangle``. The theory states that squares are a particular 
kind of rectangles in which the width and the height are equal. Therefore, the 
``Example.Square`` class will *override* ``Example.Rectangle``'s ``width`` and 
``height`` setters to ensure that those two variables have always the same 
value.
+
+Start describing your new class with a new Eolian file named 
``example_square.eo``:
+
+```
+class Example.Square (Example.Rectangle) {
+   implements {
+      Example.Rectangle.width {set;}
+      Example.Rectangle.height {set;}
+   }
+}
+```
+
+As you can see, it is derived from ``Example.Rectangle``. Regular classes must 
derive from the ``Efl.Object``, but in this case, you get that automatically, 
since ``Example.Rectangle`` already derives from ``Efl.Object``.
+
+You can also notice that this class does not provide any new method or 
property (there is no ``methods`` block). It only implements two properties, 
which currently belong to its parent class (``Example.Rectangle.width`` and 
``Example.Rectangle.height``). Furthermore, only the setters for these 
properties are implemented: Reads of these properties will be routed to the 
getter in the parent class.
+
+Next, turn the Eolian description into C files with the ``eolian_gen`` command 
(as seen in the previous tutorial). Be careful, though, there is a new 
parameter in use in this example:
+
+```bash
+eolian_gen -gchi example_square.eo -I .
+```
+
+The ``-I`` parameter tells ``eolian_gen`` where to look for other Eolian 
files, in case it needs the description of a class it does not know about. In 
this tutorial, ``Example.Square`` needs the description of 
``Example.Rectangle`` which resides in the ``example_rectangle.eo`` file. This 
file is in the same folder as ``example_square.eo``, the current folder, 
therefore, the final command requires a ``-I .`` (The dot indicates the current 
folder).
+
+This will create the boilerplate files (``.eo.h`` and ``.eo.c``) and the 
implementation file which you will fill in the next step.
+
+## Step Two: Implementing the Derived Class ##
+
+Edit the implementation file ``example_square.c``. It should contain:
+
+* An empty structure ``Example_Square_Data``. It will remain empty, because 
squares do not add any additional data to rectangles.
+* A method called ``_example_square_example_rectangle_width_set()``. This is 
the setter for the ``width`` property, inherited from the parent 
``Example.Rectangle`` class. The name of the method contains all the ancestry 
information. Don't worry, though, you will not be calling this method directly.
+* A method called ``_example_square_example_rectangle_height_set()``. As 
above, this is the setter for the ``height`` property.
+
+The implementation of these methods requires calling the parent class, 
therefore, you need to include the parent's class header file. Add a line after 
the first block of ``#include``s in the file:
+
+```c
+#include "example_rectangle.eo.h"
+```
+
+Time to think now about the implementation of these setters. They both need to 
set the ``width`` and ``height`` internal variables to the same value. But 
these variables are private to ``Example.Rectangle``, so ``Example.Square`` has 
no direct access to them. They can be accessed through the setters from 
``Example.Rectangle``, though. Only care has to be taken not to end up calling 
the setter from ``Example.Square`` currently being implemented, or an infinite 
loop would be created.
+
+In EFL, when you need to call a method from your parent instead of your 
overridden version, you can use ``efl_super()``. Its first parameter is the 
object and the second is *the class whose parent you want to call*. Write these 
implementations for the setters and it all will become apparent:
+
+```c
+EOLIAN static void
+_example_square_example_rectangle_width_set(Eo *obj, Example_Square_Data *pd 
EINA_UNUSED, int width)
+{
+   example_rectangle_width_set(efl_super(obj, EXAMPLE_SQUARE_CLASS), width);
+   example_rectangle_height_set(efl_super(obj, EXAMPLE_SQUARE_CLASS), width);
+}
+
+EOLIAN static void
+_example_square_example_rectangle_height_set(Eo *obj, Example_Square_Data *pd 
EINA_UNUSED, int height)
+{
+   example_rectangle_width_set(efl_super(obj, EXAMPLE_SQUARE_CLASS), height);
+   example_rectangle_height_set(efl_super(obj, EXAMPLE_SQUARE_CLASS), height);
+}
+```
+
+Things worth noticing:
+
+* The ``width`` and ``height`` variables are set through the regular setters 
you already used in the previous tutorial (``example_rectangle_width_set()`` 
and ``example_rectangle_height_set()``).
+* The object being passed to the setters, though, is the output of 
``efl_super()``.
+* You want to call the parent of ``Example.Square``, so the second parameter 
to ``efl_supper()`` is ``EXAMPLE_SQUARE_CLASS``.
+* These setters do not use the ``Example_Square_Data`` private data (that 
structure is actually empty, as seen above), so ``EINA_UNUSED`` is used to 
avoid compiler warnings.
+
+The ``efl_super()`` method can also be used to access older ancestors of your 
class, but that's an advanced scenario not required in this tutorial.
+
+Having written these setters, your derived ``Example.Square`` class is 
finished. The next step adds code that uses it.
+
+## Step Three: Using the Derived Class ##
+
+Open up ``eo_inherit_main.c`` and start by adding the include for 
``Example.Square``:
+
+```c
+#include "example_square.eo.h"
+```
+
+Add another method to instantiate your new class, right after 
``_rect_create()``:
+
+```c
+Example_Square *
+_square_create()
+{
+   Example_Square *square;
+
+   square = efl_add(EXAMPLE_SQUARE_CLASS, NULL,
+                    efl_name_set(efl_added, "Square"),
+                    example_rectangle_width_set(efl_added, 7));
+
+   return square;
+}
+```
+
+Observe how the side of the rectangle is set with 
``example_rectangle_width_set()``.  You could also set the ``height``, since 
both setters have the same effect on a square.
+
+Back in the main function, declare a variable to hold your new object:
+
+```c
+   Eo *rectangle, *square;
+```
+
+Now call ``_square_create()`` and print some information (right after doing 
the same thing for the rectangle object):
+
+```c
+   square = _square_create();
+
+   printf("Square is %dx%d, area is %d\n",
+          example_rectangle_width_get(square),
+          example_rectangle_height_get(square),
+          example_rectangle_area(square));
+
+   efl_unref(square);
+```
+
+Notice how you only used ``Example.Rectangle`` methods here, because 
``Example.Square`` inherits from it, and all methods that work on a rectangle 
also work on a square.
+
+Also, remember to dispose of your objects using ``efl_unref()`` if you do not 
give them a parent in ``efl_add()``.
+
+The main program (``eo_inherit_main.c``) should now look like this:
+
+```c
+#define EFL_EO_API_SUPPORT 1
+#define EFL_BETA_API_SUPPORT 1
+
+#include <Eina.h>
+#include <Efl_Core.h>
+#include "example_rectangle.eo.h"
+#include "example_square.eo.h"
+
+Example_Rectangle *
+_rect_create()
+{
+   Example_Rectangle *rectangle;
+
+   rectangle = efl_add(EXAMPLE_RECTANGLE_CLASS, NULL,
+                       efl_name_set(efl_added, "Rectangle"),
+                       example_rectangle_width_set(efl_added, 5),
+                       example_rectangle_height_set(efl_added, 10));
+
+   return rectangle;
+}
+
+Example_Square *
+_square_create()
+{
+   Example_Square *square;
+
+   square = efl_add(EXAMPLE_SQUARE_CLASS, NULL,
+                    efl_name_set(efl_added, "Square"),
+                    example_rectangle_width_set(efl_added, 7));
+
+   return square;
+}
+
+EAPI_MAIN void
+efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
+{
+   Eo *rectangle, *square;
+
+   rectangle = _rect_create();
+
+   printf("Rectangle is %dx%d, area is %d\n",
+          example_rectangle_width_get(rectangle),
+          example_rectangle_height_get(rectangle),
+          example_rectangle_area(rectangle));
+
+   efl_unref(rectangle);
+
+   square = _square_create();
+
+   printf("Square is %dx%d, area is %d\n",
+          example_rectangle_width_get(square),
+          example_rectangle_height_get(square),
+          example_rectangle_area(square));
+
+   efl_unref(square);
+
+   efl_exit(0);
+}
+EFL_MAIN()
+```
+
+If you run it, you should get this on your terminal:
+
+```bash
+Rectangle is 5x10, area is 50
+Square is 7x7, area is 49
+```
+
+## Step Four: Accessing the Parent's Private Data ##
+
+The above implementation for ``Example.Square``'s setters works because 
``Example.Rectangle`` has public setters. That is, even though ``width`` and 
``height`` are private variables visible only to ``Example.Rectangle`` they can 
be accessed by anyone through their setters and getters.
+
+The last step in this tutorial shows how a derived class can access private 
data from its parent, which is also a common operation in OOP.
+
+The first thing done in the implementation file ``example_rectangle.c`` is to 
define the ``Example_Rectangle_Data`` structure, which is therefore only 
accessible from that file. If ``Example.Square`` has to have access to this 
structure, it has to be defined in a common header.
+
+Create an ``example_rectangle_private.h`` file and move the structure there:
+
+```c
+typedef struct
+{
+   int width, height;
+} Example_Rectangle_Data;
+```
+
+In ``example_rectangle.c``, replace the structure with an include :
+
+```c
+#include "example_rectangle_private.h"
+```
+
+Finally include the header *also* from ``example_square.c``. At this point, 
the implementation for ``Example.Square`` can understand the private data of 
its parent ``Example.Rectangle``. You only need to retrieve a pointer to that 
data, using ``efl_data_scope_get()``. This is how your square setters should 
look now:
+
+```c
+EOLIAN static void
+_example_square_example_rectangle_width_set(Eo *obj, Example_Square_Data *pd 
EINA_UNUSED, int width)
+{
+   Example_Rectangle_Data *rect_pd = efl_data_scope_get(obj, 
EXAMPLE_RECTANGLE_CLASS);
+   rect_pd->width = width;
+   rect_pd->height = width;
+}
+```
+
+And likewise for the ``height`` setter.
+
+Notice how the first parameter to ``efl_data_scope_get()`` is the object for 
which you want to retrieve the private data, and the second parameter is the 
*ancestor class*. You can retrieve the private data for any class, as long as 
it belongs to your hierarchy.
+
+> **NOTE:**
+> For performance reasons, no runtime check is performed to ensure that the 
requested class actually belongs to your ancestry. If you want to avoid 
*undefined behavior* use ``efl_data_scope_safe_get()``.
+
+Once you have the pointer to the private data of ``Example.Rectangle`` you can 
write to both ``width`` and ``height`` as you were doing before.
+
+Finally, if you need to keep this private data pointer alive for a long time, 
it is worth reading about ``efl_data_ref()`` and ``efl_data_unref()``. These 
methods will make sure that the enclosing object is not destroyed until you are 
done working with its private data.
+
+## Step Five: Per-Object Method Override ##
+
+One final function worth knowing is ``efl_object_override()``. It allows 
changing some method's implementation for a particular object, just like 
derived classes do, but on a single object.
+
+Its use case is a bit advanced so it will not be shown in this tutorial. It is 
related to class inheritance, though, so it deserves being mentioned.
+
+## Summary ##
+
+This tutorial has taught you:
+
+* **Derived classes** can be created with Eolian.
+* **Methods overridden by the derived class** are automatically called when a 
derived class object is used.
+* **Public data** of the parent class can be accessed through its **public 
accessors**.
+* **Private data** of the parent class can be accessed through 
``efl_data_scope_get()``.
+* **Method implementations on individual objects** can be overridden using 
``efl_object_override()``.
+
+## Further Reading ##
+
+[Creating New Classes](eo-classes.md)
+:    Teaches the basis of class creation with Eo
+
+[Multiple Inheritance](eo-multiinherit.md)
+:    Moves forward and explains how to inherit from more than one class at a 
time
\ No newline at end of file

-- 


Reply via email to