0

To my understanding, C does not have the concept of objects, then how can Python be implemented in C to support something that C can not? How is the concept of "Object" modeled in C? What is internally used?

Edit : Reading through the comments, I am interested in this specific implementation of Python which "uses" C to make the whole thing work. More specifically how is a python "object" represented in C.

As an example in comments, something like a Banking System can use "Classes" to model it, like so how can C model the Python concept of Object.

20
  • 3
    Python isn't written in C. Python is a programming language, a programming language is an abstract mathematical idea. It is written in English. Commented May 23, 2021 at 9:35
  • 9
    Python doesn't have the concept of bank accounts, then how can a banking system be written in Python? Commented May 23, 2021 at 9:39
  • 1
    @JamesMcLeod I am now convinced this is a broad question to be answered and I will remove this question soon
    – Alice
    Commented May 23, 2021 at 9:55
  • 2
    @JörgWMittag Interestingly, a couple of years ago, you just answered very similar questions, without playing with the words (see proposed duplicate).
    – Christophe
    Commented May 23, 2021 at 10:07
  • 2
    @JörgWMittag Yes I know. I do not disagree with your point (see how I talked about your remark with Alice for advice). Most of the people make intuitively the difference between a language specification and an implementation, but are not necessarily used to express ot clearly in the wording ;-)
    – Christophe
    Commented May 23, 2021 at 10:21

2 Answers 2

14

Higher level abstractions are routinely implemented with lower level building blocks.

For example, C higher level language constructs are themselves implemented with lower level assembler instructions. And the same applies to object orientation, which is often implemented with non-object oriented techniques.

Objects are made of data and behavior. C does not know objects, but it knows data structures and functions:

  • To implement "methods" that would operate on data structures in C, to emulate basic object orientation, you can define C functions that take a pointer to the data structure as one of their argument (usually the first). Of course, doing this manually is not practical, and you can easily forget to call the method to initialise an object that was just allocated. But if you have a compiler, it's easy to make sure that this is done systematically. It's also easy for to transform a call such as a.do_something(b,c,d) into do_something(a,b,c,d).

  • To implement methods that change depending on some condition, in C you can use function pointers. A function pointers can point to any function that have a given "signature" (i.e. return type and argument with types). This allows to implement some dynamic dispatching such as what is needed for polymorphism. It is then easy to enrich the inital data structure with some function pointers. Or to enrich it with a pointer to another datastructure that holds the name and function pointer of each relevant method corresponding to a guiven class

  • If the language implemented allows functions/methods with variable number of arguments, you could opt for reduced number of arguments in C, such as the pointer to the data structure holding the object's data, a pointer to a list of arguments.

  • If the language implemented allows for dynamic typing, all method arguments discussed so far would simply be a data structure that holds information about the type of the data, and the data itself, i.e. in C a pair of pointers to different structures).

  • If you need to allow inheritance and multiple inheritance, it gets tricky, but you would work either on generating a composed data structures, or organise the data structure with some pointers that point to a parent object, along with the code to properly access the data following the chain.

  • And for every other language construct, there is probably already a solution. Because ultimately, the thing will run on a microprocessor with very low-level elementary machine instructions.

7
  • 2
    your first line was all that I needed to relate with to understand, the rest of the answer is unfortunately above my understanding as of now, but I will surely return to this answer when I understand more about programming, many thanks for answering this whilst also pointing out in a nice manner in comments :)
    – Alice
    Commented May 23, 2021 at 10:51
  • 2
    This is an excellent answer. To my mind the only thing that isn't made clear to @Alice, is an example how an "object" is actually laid out in memory, including the vtables. Whereas OO languages tend to portray objects misleadingly as things that contain both fields and methods, in fact what exists are methods which operate on objects of the given class (i.e. the methods exist once in memory for each class), and then there are structures which represent each instantiated object, and which contain both the explicit fields of that instance, and contain... (1/2)
    – Steve
    Commented May 23, 2021 at 12:53
  • 2
    ...a further set of fields (which in OO languages are not visible or explicit) which are pointers to the class methods. The "object constructor" which is called once when each instance is created, contains logic (again, not visible or explicit in the OO language itself) which wires up these implicit instance fields, so that they point to the class methods. Every object goes through this hidden "wiring-up" process. (2/2)
    – Steve
    Commented May 23, 2021 at 12:53
  • 1
    @Steve thanks for this feedback and the suggestions. I hesitated to provide some more information about the memory layout, and. tables. I considered providing a link to the first article mentioned in this answer on so. But I thought that this might be too specific for C++ and not necessarily be transposable as such to python. And thank you also for pointing out that data+functions is necessarily simplified, as it does not take into account accessibility. Object composition is indeed… (1/2)
    – Christophe
    Commented May 23, 2021 at 13:14
  • 1
    @Steve … a little bit more subtle (and powerful). I used the data+function viewpoint mainly to address the low-level implementation considerations. But you‘re right: this implementation consideration should not mislead Alice to get fundamental OOP principles wrong
    – Christophe
    Commented May 23, 2021 at 13:19
3

TL;DR: different level of abstractions. There is really no such thing as an object, there are just 1’s and 0’s and interpretations of them.

The CPU doesn’t know about objects, so the same question would apply for it: how can you you have a compiler for a language with objects, when the CPU it targets doesn’t know about objects? And the answer is the same, objects are an abstracts where data and functions are bound together by a convention/standard and it is this convention/standard that really defines an object. While the standard isn’t defined in C, C is able to create an implementation of this standard.

This is in fact how C++ and Obj-C were first created. C was a good choice for doing this, because of its cross platform support and hardware support. This made it possible to write a C++ compiler that not only ran on many different platforms, it also compiled for the many different platforms.

To go back to the CPU example, the CPU doesn’t even know about strings, it just knows about bytes, typically having a register size of 1, 2, 4 or 8 bytes. How can it deal with strings? Easy, it doesn’t. The compiler has a convention/standard that it imposes on itself. Strings in C are really just null terminated chunks of memory. In Python, a string is a variable sized structure that takes 49 to 80 bytes in memory PLUS the chunks of memory that is the “characters”. But all of this is totally irrelevant to the CPU. A python programs “strings” aren’t going to be C strings even though the program is compiled to C, because when the code is compiled to C it isn’t going to use the C conventions for strings when dealing with python strings, it will use python conventions, executed in C.

2
  • 3
    The first C++ compiler I used was CFront which translated C++ into C. Which was then compiled by the C compiler. That was before exceptions, which would be non-trivial to translate into plain C.
    – gnasher729
    Commented May 23, 2021 at 18:38
  • thank you for this explanation, it helps a lot with my understanding
    – Alice
    Commented May 24, 2021 at 1:25

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.