I was thinking a little bit how to code SymPy in C. I want to use OOP,
since that's what I am used to in Python. So C++ would be a natural
choice.
But then one notices that almost all robust programs are done in C,
like Python, or the linux kernel. In our case, we want to extend
Python,
and all other good Python libraries use C (like numpy, or Mercurial,
etc.). So there are probably good reasons for that.
So I was looking how to do OOP in C. I found this paper from 1993:
http://www.cs.rit.edu/~ats/books/ooc.pdf
it explains how to code OOP in ansi C, I read through it, but it's too complex.
Then I found this really interesting page:
http://ldeniau.web.cern.ch/ldeniau/html/oopc.html
Look at the C Object System (COS), which is a set of macros in C, that
allows you to program like in C++. There is also a draft paper how it works,
but it's slower than g++. It's nice, but it's just too academic and noone use it
(yet)...
Then I decided to look at some good, real life programs. I found this:
http://barracudaserver.com/WP/DeviceControl/OOIntro.html
and that's what I like. It's simple and it does the job and it solves
a real problem,
not some academic one. Here is an example of the same C and C++ code
side by side:
http://barracudaserver.com/WP/DeviceControl/C_and_CPP_source.html
That shows, it's really the same thing.
Here is another example of C and C++ code side by side:
http://www.eventhelix.com/RealtimeMantra/basics/object_oriented_programming_in_c.htm
So the only thing, that seems more complicated in C compared to C++ is
virtual functions invocations:
http://www.eventhelix.com/RealtimeMantra/basics/ComparingCPPAndCPerformance2.htm
where one needs to handle VTable manually, but as shown, it's not
really difficult or messy. The only thing I don't like is that one
needs to use numbers (e.g. pVTable[1]) to access the correct method:
C++: pShape->Draw();
C: (pShape->pVTable[0].pFunc)(pShape);
C++: pShape->MoveTo(100, 100);
C: (pShape->pVTable[1].pFunc)(pShape, 100, 100);
Which is error prone. But one can make macros, so that one can write
Shape_MoveTo_virtual(pShape, 100, 100)
and it will get translated to
(pShape->pVTable[1].pFunc)(pShape, 100, 100);
But still I find it complex. Let's make it more simple. So I digged a
little more and I found this:
http://flinflon.brandonu.ca/dueck/1997/62285/virtualc.html
And that's finally what I was looking for. It's simple, explicit, pure
C and fully object oriented with virtual functions and VMT.
Do you know about some opensource pure C program, that uses this
design, so that we can learn from it?
Ondrej
So Kirill suggested it's the gobject in glib (used by gtk, gnome, gimp, etc..):
http://library.gnome.org/devel/gobject/unstable/
So there are a lot of programs to study.
And when one doesn't neet the whole machinery (it's probably an
overkill for our purposes),
one can just use structs with function pointers, as described in my
previous email.
Ondrej
First of all, sorry for not replying for so long...
Ondrej, I think I agree with Pearu here -- we do not need full OOP and
we only need to write only small parts in C.
Also, look at any python module, or Python itself:
Consider for example Python list.
- it inherits from object, so it's struct starts with macro
PyObject_VAR_HEAD
Think of it as of "list : object" in C++
- Then we have PyList_Type which describes how to allocate/deallocate
list objects, method table, etc...
- Then we have functions like PyList_New, PyList_GetItem, etc, to
construct objects, acces their elements, etc...
- 'virtual' methods are declared in list_methods (which is referenced
from PyList_Type.tp_methods)
So, why not to stick to Python approach?
BTW: Cython also allows to define new Python types which is cool!
--
Also, if we need pure C virtual functions, something like following will
do:
typedef struct {
struct BasicMeth *vtable;
/* blah-blah-blah */
} Basic;
typedef struct {
Basic_VAR_HEAD /* this will include common data members from basic
*/
PyObject* args;
} Add;
/* later, e.g. */
Basic *expr = Add_New(...);
expr->vtable->expand(expr);
--
Всего хорошего, Кирилл.
http://landau.phys.spbu.ru/~kirr/aiv/
But this only allows exactly one subclass of PyObject. Otherwise the
subclass would have to also provide this kind of macro.
>
> Think of it as of "list : object" in C++
>
> - Then we have PyList_Type which describes how to allocate/deallocate
> list objects, method table, etc...
>
> - Then we have functions like PyList_New, PyList_GetItem, etc, to
> construct objects, acces their elements, etc...
>
> - 'virtual' methods are declared in list_methods (which is referenced
> from PyList_Type.tp_methods)
>
>
> So, why not to stick to Python approach?
You can handle all methods in the vtable, ok.
But then you still need to pass all variables in the struct as macros,
so that derived objects can declare them as the first members in the
struct.
Without using macros, you'd have to copy the same change in the Basic
object to all derived objects by hand. And with using macros, I don't
find it very convenient.
>
> BTW: Cython also allows to define new Python types which is cool!
>
>
> --
>
> Also, if we need pure C virtual functions, something like following will
> do:
>
> typedef struct {
> struct BasicMeth *vtable;
>
> /* blah-blah-blah */
> } Basic;
>
> typedef struct {
> Basic_VAR_HEAD /* this will include common data members from basic
The problem with Basic_VAR_HEAD is that it would have to contain the
whole basic struct, but as a macro. Maybe without the vtable.
I don't find it very convenient to use C macros for the definition of
the whole class.
> */
>
> PyObject* args;
> } Add;
>
>
> /* later, e.g. */
> Basic *expr = Add_New(...);
>
> expr->vtable->expand(expr);
I put my code here:
http://wiki.sympy.org/wiki/Playing_with_SymPy_design_in_C
The disadvantage of it is that if you add some private variable to the
basic struct, you would have to add it by hand to all the derived
classes. Which is not the way. Or use macros, which is imho not a way
either. Or just use C++.
Ondrej