111

It seems that C has its own quasi-objects such as 'structs' that can be considered as objects (in the high-level way that we would normally think).

And also, C files themselves are basically separate "modules", right? Then aren't modules kind of like 'objects' too? I'm confused as to why C, which seems so similar to C++, is considered a low-level "procedural" language where as C++ is high-level "object-oriented"

*edit: (clarification) why and where, is the line drawn, for what an 'object' is, and isn't?

Dark Templar
  • 6,223
  • 16
  • 46
  • 46
  • 47
    All - why the down votes? It's a basic question but not a bad one. – Jon Hopkins Oct 10 '11 at 20:59
  • 11
    You can use OO principles effectively in C (and people who write good C code typically do), but the language is not built around making it easy, as many more recent languages are. – asveikau Oct 10 '11 at 22:47
  • 5
    C simply has a different, simpler, and (to be honest) better *defined* (at least among the open-source community) approach to data abstraction. C++ tends to be an abstraction powerhouse and allows for many great things, but comes with a cost of having to understand how to [not] use them properly, which is, more often than not, quite missing in common programs. See my full answer for more details. – Yam Marcovic Oct 10 '11 at 23:55
  • I plan on accepting them in bulk soon... no worries man!! – Dark Templar Oct 11 '11 at 06:52
  • 1
    Shortly: Structs can't have methods. (Pointer to a function doesn't quite cut it). – SF. Oct 11 '11 at 07:01
  • 1
    It is possible to do object-based programming in C, with some difficulty. But that doesn't make it object *oriented*. – Wedge Oct 11 '11 at 09:24

13 Answers13

114

It seems that C has its own quasi-objects such as 'structs' that can be considered as objects

Let's together you and I read through the Wikipedia page on object oriented programming and check off the features of C-style structs that correspond to what is traditionally considered to be object-oriented style:

(OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions

Do C structs consist of fields and methods together with their interactions? No.

Programming techniques may include features such as data abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance.

Do C structs do any of these things in a "first class" way? No. The language works against you every step of the way.

the object-oriented approach encourages the programmer to place data where it is not directly accessible by the rest of the program

Do C structs do this? No.

An object-oriented program will usually contain different types of objects, each type corresponding to a particular kind of complex data to be managed or perhaps to a real-world object or concept

Do C structs do this? Yes.

Objects can be thought of as wrapping their data within a set of functions designed to ensure that the data are used appropriately

No.

each object is capable of receiving messages, processing data, and sending messages to other objects

Can a struct itself send and receive messages? No. Can it process data? No.

OOP data structures tend to "carry their own operators around with them"

Does this happen in C? No.

Dynamic dispatch ... Encapsulation ... Subtype polymorphism ... Object inheritance ... Open recursion ... Classes of objects ... Instances of classes ... Methods which act on the attached objects ... Message passing ... Abstraction

Are any of these features of C structs? No.

Precisely which characteristics of structs do you think are "object oriented"? Because I can't find any other than the fact that structs define types.

Now, of course you can make structs that have fields that are pointers to functions. You can make structs have fields that are pointers to arrays of function pointers, corresponding to virtual method tables. And so on. You can of course emulate C++ in C. But that is a very non-idiomatic way to program in C; you'd be better off just using C++.

And also, C files themselves are basically separate "modules", right? Then aren't modules kind of like 'objects' too?

Again, what characteristics of modules are you thinking of that makes them act like objects? Do modules support abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance?

Abstraction and encapsulation are pretty weak. Obviously modules are modular; that's why they're called modules. Messaging? Only in the sense that a method call is a message and modules can contain methods. Polymorphism? Nope. Inheritance? Nope. Modules are pretty weak candidates for "objects".

Eric Lippert
  • 45,799
  • 22
  • 87
  • 126
  • 16
    I disagree that "emulating C++" (your term) isn't idiomatic C. One counter example would be how an OS kernel typically implements file operations - take Linux as an example, where you have structs full of function pointers. They may be somewhat "domain-specific" idioms (restricted to writing drivers on *nix, say), but they are recognizable and do the job cleanly enough for some purposes. There are also some examples of user mode libraries that do some notion of OO well enough; take Gtk+ and the libraries it depends on. Call it hacky and you may be right, but these are not terrible to work with – asveikau Oct 10 '11 at 23:16
  • 6
    @asveikau: Doesn't the idea that a practice is unusual (even if not unheard of) and "hacky" mean that it is, by definition, not idiomatic? – Adam Robinson Oct 11 '11 at 01:50
  • 1
    @AdamRobinson - "Hacky" is a subjective term so I might have been exaggerating slightly. I just cited two projects (Linux kernel, Gtk+/glib) that have their own idioms, and from that vantage point I don't think you can deny that the idioms I'm talking about do exist in their niches. Do the idioms have to be universal to be idiomatic? I don't think so. [Consider that the Greek root of "idiom" means "of one's own". :-)] Disciplined programmers who have done serious work in C should be able to recognize these idioms and/or quickly adapt to them and generally be productive. – asveikau Oct 11 '11 at 02:36
  • 24
    @asveikau: Sure, there are things you can do to make C programs more OO in style. But as you say, it requires discipline to do so; the language features themselves do not naturally lead you towards encapsulation, polymorphism, class inheritance, and so on. Rather, the developer can impose that pattern on the language. That doesn't mean that structs are logically the same thing as objects. Heck, you can program in an OO style in Lisp too, but that doesn't mean that cons cells are objects. – Eric Lippert Oct 11 '11 at 05:48
  • 3
    @asveikau, may I suggest that your (mis)interpretation of "idiom" as "of one's own" is mildly... idiosyncratic? :) – Benjol Oct 11 '11 at 05:57
  • Eric: I don't disagree, and I'm sure these points were clear to you at the onset. I just felt my points were a fair supplement to your answer. Your answer steers very strongly towards "no, don't do it/don't think of it that way"; I was trying to say, hey, it's been done, in some cases well, you may come across it in some projects, and when it's done right the results are not always so bad. But in general I think I agree with your position more than I'm letting on. @Benjol Nice, I just hope nobody describes me with a certain other word derived from this root, something ending in -t perhaps :P – asveikau Oct 11 '11 at 06:12
  • @Eric Lippert: I agree in general, but you could come up with a better example than Lisp. Common Lisp has rich OOP support built into the language (CLOS). – Nemanja Trifunovic Oct 11 '11 at 12:36
  • 6
    @NemanjaTrifunovic: Read that sentence again: "You can program in an OO style in Lisp too, **but that doesn't mean that cons cells are objects**." My point is not that you cannot program OO style in Lisp, as you can. My point is that doing so does not automatically make the fundamental building blocks of Lisp "objects". Similarly, you can program in an OO style in C, but that doesn't mean that structs (or modules) are objects. – Eric Lippert Oct 11 '11 at 13:07
  • I don't disagree with your answer in spirit, but just to point out that if you consider a struct with pointers to code and a heavy, annoying syntax then your answer is nearly entirely wrong (It's still missing encapsulation, but everything else is there). That is how they implemented OO before C++ existed. You can even practice advanced OO concepts like inheritance and polymorphism by overriding the function pointers. – Bill K Oct 11 '11 at 15:32
  • 1
    There are things you can do that'll make assembly language more OO in style. I hope noones going to argue therefore assembly is OO. And 'C' is just a pimped-up assembler really. – timday Oct 11 '11 at 19:44
  • 1
    @Bill K: I think I said that already. See the paragraph that begins "*Now, of course you can make structs that have fields that are pointers to functions. You can make structs have fields that are pointers to arrays of function pointers, corresponding to virtual method tables...*" – Eric Lippert Oct 11 '11 at 20:02
  • Good point, sorry for not reading thoroughly enough, but knowing that why did you still say structs couldn't contain code only data? I thought that kylben's answer was much more to the point... but as I said I didn't disagree with your answer at all--conceptually it's accurate. – Bill K Oct 11 '11 at 20:20
  • 10
    @BillK: Structs cannot contain code in C. Structs can contain *function pointers*, which are *data*. Function pointers aren't *code*. *Code* is a textual artifact created by a programmer. – Eric Lippert Oct 11 '11 at 21:36
  • "the object-oriented approach encourages the programmer to place data where it is not directly accessible by the rest of the program" -> C structs can do this, with opaque pointers. The APR library does this constantly. – Artefact2 Oct 12 '11 at 05:35
  • 1
    This answer misses the point. It shows that C structs are not OO; it does *not* show that C isn’t. The whole point, in my opinion, is that C, while not making it impossible, doesn’t *invite* writing in an OOP style. Now, it’s true that the OP explicitly asked after structs and here this answer is spot-on. But what if the OP had asked whether *functions in C++* were OO? – Konrad Rudolph Oct 12 '11 at 15:41
  • @KonradRudolph Are you suggesting that this answer would have been an inappropriate response to a different, hypothetical question? If so, I wholeheartedly agree. :P – Dan J Oct 13 '11 at 17:51
  • @djacobson No, I say that if the question had been worded differently, but asked a fundamentally identical question („is [X] OOP“, where X is not OOP), the inappropriateness would have been obvious. – Konrad Rudolph Oct 13 '11 at 17:54
  • Ah, I understand: the title of the question asks about X, while its body - and this answer - uses a component of X as an example. Would an acceptable extension be to say that, now that C structs have been shown as "not OOP", we can add that no other fundamental C construct meets the feature set expected of OOP, and therefore C as a whole should not be considered an "object-oriented language"? – Dan J Oct 13 '11 at 17:59
  • @djacobson Yes. I only mentioned this because structs are really a red herring, and often lead to misunderstandings in C about its capabilities of handling object orientation – which C *does* allow (see GObject, WinAPI and similar frameworks), it just doesn’t provide good support for it. This answer isn’t even bad (well, of course not), I just feel it has accumulated an embarrassing number of upvotes, compared to other, more complete answers. – Konrad Rudolph Oct 13 '11 at 18:08
  • 1
    One of the distinguishing features of OOP is the use of dynamic dispatch (method selection) based on the class of the object that receives the message. In C you can put function pointers in struct's, but you still do not have dynamic dispatch (at least, not directly in the language, i.e. you have to implement it yourself). – Giorgio Apr 13 '13 at 13:52
54

The key word is "oriented", not "object". Even C++ code that uses objects but uses them like structs is not object oriented.

C and C++ can both do OOP (aside from no access control in C), but the syntax for doing it in C is inconvenient (to say the least), while the syntax in C++ makes it very inviting. C is oriented to procedural, while C++ is oriented to objects, despite nearly identical core capabilities in that regard.

Code that uses objects to implement designs that can only be done with objects (usually meaning taking advantage of polymorphism) is object oriented code. Code that uses objects as little more than bags of data, even using inheritance in an object oriented language, is really just procedural code that is more complicated than it needs to be. Code in C that uses function pointers that are changed around at runtime with structs full of data is kinda doing polymorphism, and could be said to be "object oriented", even in a procedurally oriented language.

kylben
  • 2,288
  • 14
  • 13
  • 5
    +1 For pointing our C can be OO. It's not convenient, but it can be done. – dietbuddha Oct 11 '11 at 04:04
  • It's easer to create objects in VBA, but I wouldn't consider it object 'oriented' either. – JeffO Oct 11 '11 at 12:09
  • VBA I call "object based". It uses objects, but not polymorphically, and in the little bit of work I've done in it, I'm not sure you can even do polymorphism no matter what kind of code acrobatics you try. It's basically a procedural language with encapsulation. – kylben Oct 11 '11 at 12:17
  • 3
    Most languages can act as an OO, functional or pretty much any style of language. the difference is the "Oriented" and I'd never heard it put that way before. I wish I could vote this up 3 times and accept it, it's the right answer. – Bill K Oct 11 '11 at 15:34
  • Thanks, @BillK. I'd hate to see how OOP gets implemented in SQL, though. – kylben Oct 11 '11 at 16:32
  • 1
    @kylben It wouldn't be too much of a stretch to store SQL code in the table then extract and execute (making the table your object) It would be an interesting experiment. Actually it's a little tempting... – Bill K Oct 11 '11 at 20:07
  • you can even do object oriented programming in an assembly language. you just have to code disciplined. – Rommudoh Oct 12 '11 at 10:55
  • "C and C++ can both do OOP (aside from no access control in C)": (1) access control is not a distinguishing feature of OOP because it is found in functional languages and procedural languages, (2) you can achieve access control in C by means of opaque pointers. – Giorgio Apr 13 '13 at 13:55
20

Based on the very highest level principals:

An object is an encapsulation of data and behaviour in an interlinked way such that they operate as a whole that can be instantiate multiple times and worked on as a black box if you know the external interface.

Structs contain data but no behaviour and therefore can not be considered objects.

Modules contain both behaviour and data but are not encapsulated in such a way that the two are related and certainly can't be instantiated multiple times.

And that's before you get onto inheritance and polymorphism...

Jon Hopkins
  • 22,734
  • 11
  • 90
  • 137
  • How come behavior and data in modules aren't related? Aren't member functions basically the 'behavior' on the data that exist inside the module? – Dark Templar Oct 10 '11 at 21:05
  • 4
    The problem is that they are not encapsulated, not that they are not related. – Eoin Carroll Oct 10 '11 at 21:08
  • Actually objects are centred principally around *behaviour*, not data. Data is/should be a second class citizen in OOP. Structs, instead are centred around data and have no behaviour. – Sklivvz Oct 11 '11 at 00:27
  • 1
    @Dark Templar - What Eoin said... It's in the nature of the relationship. I can see where you're coming from - you could certainly use Structs within a module in such a way that it emulated *some* very very basic elements of OO but much of what you'd be doing would rely on the programmer sticking to a set of self imposed rules rather than having the language enforce it. And why would you bother? You're getting none of the benefits of OO - no inheritance for instance - and you're restricting yourself. – Jon Hopkins Oct 11 '11 at 06:20
  • This is a better answer than the one marked correct. – zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz Nov 02 '11 at 18:34
8

"structs" are data only. The usual quick and dirty test of "object orientation" is: "Is there a structure that allows code and data to be encapsulated as a single unit?". C fails that, and is hence procedural. C++ passes that test.

Brian Knoblauch
  • 4,170
  • 1
  • 17
  • 20
  • 6
    There are workarounds, structs can have static function pointers to member functions. They will need explicit `this` pointer, but in that case, data and means to process data will be encapsulated inside the structure. – Coder Oct 10 '11 at 20:50
  • @Brian Knoblauch: but isn't a C file itself an encapsulation of data and code?? – Dark Templar Oct 10 '11 at 20:51
  • @DarkTemplar In a sense, yes, but unless you manage to create translation units, compile them and load them into the running process at runtime, this does you little good. –  Oct 10 '11 at 20:53
  • translation units? >. – Dark Templar Oct 10 '11 at 20:56
  • @Dark Templar: A translation unit is a source file plus anything `#include`d into it, and minus anything removed by not being conditionally included (`#if`, `#ifdef`, and the like). – David Thornley Oct 11 '11 at 13:45
5

C, just like C++, has the capability of providing Data Abstraction, which is one idiom of the object-oriented-programming paradigm that existed before it.

  • C structs can have data (and that's their main purpose)
  • C structs can also define function pointers as data
  • C structs can and often have a set of functions associated with them, just like methods, only the this pointer is not passed implicitly, but you must specify it explicitly as the first argument to each method designed to handle the specified struct. C++ does this automatically for you, both when you define and call class/struct methods.

OOP in C++ extends the means to abstract data. Some say it's harmful, while others consider it a good tool when used correctly.

  • C++ makes the this pointer implicit by not requiring the user to pass it into "methods of the class/struct" as long as the type can be (at least partly) identified.
  • C++ lets you restrict access to certain methods (class functions), and hence allows for more "defensive programming" or "idiot-proofing".
  • C++ encourages abstractions by providing stronger type-safety by introducing
    1. The new operator instead of malloc + cast
    2. Templates instead of void pointers
    3. Inline functions receiving typed-values instead of macros
    4. Built in Polymorphism which you don't have to implement yourself, that lets you create abstraction hierarchies, contracts and specializations.

However, you'll find many C "hackers" preaching for how C is perfectly capable of just the right amount of abstraction and how the overhead created by C++ only distracts them from solving the actual problem.

Inefficient abstracted programming models where two years down the road you notice that some abstraction wasn't very efficient, but now all your code depends on all the nice object models around it, and you cannot fix it without rewriting your app. -- Linus Torvalds

Others tend to look at it in a more balanced way, accepting both the advantages along with the disadvantages.

C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off. -- Bjarne Stroustrup

Yam Marcovic
  • 9,270
  • 2
  • 27
  • 29
2

You need to look at the other side of the coin: C++.

In OOP, we think of an abstract object (and design the program accordingly), for example a car that can stop, accelerate, turn left or right, etc. A struct with a bundle of functions simply does not fit the concept.

With "real" objects we need to hide the members for instance, or we can also have inheritance with a real "is a" relationship and many more.

AFTER READING THE COMMENTS BELOW: Well it's right that (almost) everything can be done with C (that is always true), but at first glance I thought that what separates c from c++ is the way you think when designing a program.

The only thing that really makes the difference is the imposing of policies by the compiler. i.e pure virtual function, and such. but this answer will only relate to technical issues, but I think the the main difference (as mentioned) is the original way you think while you code, since C++ gives you a better built in syntax for doing such things, instead of doing OOP in a somewhat clumsy way in C.

Guy L
  • 179
  • 1
  • 7
  • Not really sure why a struct with a "bundle of functions" doesn't fit the concept? +1 for the answer though – Dark Templar Oct 10 '11 at 20:55
  • 1
    Aside from access control (private/protected/public) everything else can be done with structs. – Coder Oct 10 '11 at 20:58
  • 1
    @DarkTemplar: Well, you *can* try to emulate OOP in C (people have actually written ebooks on that topic and do it in the real world, albeit very rarely), like you can try emulating functional programming in Java. But C provides zero help for it, hence C the language isn't object-*oriented*. –  Oct 10 '11 at 20:58
1

You kind of said it yourself. While C has things that are kind of like objects, they are still not objects, and that is why C is not considered an OOP language.

apaderno
  • 4,014
  • 8
  • 42
  • 53
ryanzec
  • 2,747
  • 3
  • 24
  • 30
1

Object Oriented refers to both an architectural pattern (or even a meta-pattern), and, the languages that have features to help implement or mandate using this pattern.

You can implement an "OO" design (Gnome desktop is perhaps the best example of OO done in pure C), I have even seen this done with COBOL!

However being able to implement an OO design dose not make the language OO. Purists would argue that Java and C++ are not truly OO as you cannot override or inherit the basic "types" such as "int" and "char", and, Java does not support multiple inheritance. But as they are the most widely used OO languages and support most of the paradigm most "real" programmers who get paid to produce working code regard them as the OO languages.

C on the other hand supports only structures (as do COBOL,Pascal and dozens of other procedural languages), you could argue that supports multiple inheritance in that you can use any function on any piece of data but most would regards this as a bug rather than a feature.

James Anderson
  • 18,049
  • 1
  • 42
  • 72
0

Let's just look at the definition of OO:

  • Messaging
  • Encapsulation
  • Late Binding

C provides none of those three. In particular, it doesn't provide Messaging, which is the most important one.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
  • 1
    I think I'd have to disagree with that. You can most certainly have messaging in C — work with Objective C APIs from C and you find that out in depth — and late binding can be done through function pointers, but you don't get lots of syntactic sugar to hide it. (Encapsulation is actually easy in C; pointers to incomplete structure types do the job perfectly.) – Donal Fellows Oct 11 '11 at 08:03
  • Inheritance is also considered important in OO, and C doesn't do that. The closest thing to encapsulation in C is separate files that can have internal (`static`) functions and data members. – David Thornley Oct 11 '11 at 13:39
  • @DonalFellows, the actual message passing in Objective-C could be easily implemented as a C99 macro. The only thing that the compiler has going for it is that it generates all the necessary structures statically from a few lines of high level code. Most if not all features are available from the C API. –  Oct 11 '11 at 15:22
0

There are a number of key ingredients to OO, but the big ones are that the majority of code does not know what is inside an object (they see the surface interface, not the implementation), that the state of an object is a managed unit (i.e., when the object ceases to be, so does its state), and when some code invokes an operation on an object, they do so without knowing exactly what that operation is or involves (all they do is follow a pattern to throw a “message” over the wall).

C does encapsulation just fine; code which does not see the definition of a structure can't (legitimately) peek inside it. All you need to do that is to put a definition like this in a header file:

struct FooImpl;
typedef struct FooImpl *Foo;

Of course, there will be a need for a function that builds Foos (i.e., a factory) and that should delegate some of the work to the allocated object itself (i.e., through a “constructor” method), and also to have a way of disposing of the object again (while letting it clean up via its “destructor” method) but that's details.

Method dispatch (i.e., messaging) can also be done through the convention that the first element of the structure is actually a pointer to a structure full of function pointers, and that each of those function pointers must take a Foo as its first argument. Dispatch then becomes a matter of looking up the function and calling it with the right argument rewrite, which isn't that hard to do with a macro and a little cunning. (That table of functions is the core of what a class really is in a language like C++.)

Furthermore, that gives you late binding too: all the dispatch code knows is that it is invoking a particular offset into a table pointed at by the object. That only needs to be set during the allocation and initialization of the object. It's possible to go with even more complex dispatch schemes that buy you more runtime dynamism (at a cost of speed) but they're cherries on top of the basic mechanism.

Yet that doesn't mean that C is an OO language. The key is that C leaves you to do all the tricky work of writing the conventions and dispatch mechanism yourself (or use a third-party library). That's a lot of work. It also doesn't provide syntactic or semantic support, so implementing a full class system (with things like inheritance) would be unnecessarily painful; if you're dealing with a complex problem that is well described by an OO model, an OO language will be very useful in writing the solution. The extra complexity can be justified.

Donal Fellows
  • 6,347
  • 25
  • 35
0

I think C is perfectly fine and decent for implementing object-oriented concepts, shrug. Most of the differences as I see it between the common denominator subset of languages considered object-oriented are minor and syntactical in nature from my sort of pragmatic viewpoint.

Let's start with, say, information hiding. In C we can achieve that by simply hiding the definition of a structure and working with it through opaque pointers. That effectively models the public vs. private distinction of data fields as we get with classes. And it's easy enough to do and hardly anti-idiomatic, as the standard C library relies on this heavily to achieve information hiding.

Of course you lose the ability to easily control exactly where the structure is allocated in memory by using opaque types, but that's only a noteworthy difference between, say, C and C++. C++ is definitely a superior tool when comparing its ability to program object-oriented concepts over C while still maintaining control over memory layouts, but that doesn't necessarily mean that Java or C# is superior to C in that regard, since those two make you completely lose the ability to control where objects are allocated in memory.

And we do have to use a syntax like fopen(file, ...); fclose(file); as opposed to file.open(...); file.close(); but big whoop. Who really cares? Maybe just someone who leans heavily on auto-completion in their IDE. I do admit that can be a very useful feature from a practical standpoint, but maybe not one that necessitates a discussion about whether a language is suitable for OOP.

We do lack the ability to effectively implement protected fields. I'll totally submit there. But I don't think there's a concrete rule that says, "All OO languages should have a feature to allow subclasses to access members of a base class that should still not be accessed by normal clients." Besides I rarely see use cases for protected members that aren't at least a little bit suspicious of becoming a maintenance hurdle.

And of course we have to "emulate" OO polymorphism with tables of function pointers and pointers to them for dynamic dispatch with a little more boilerplate to initialize those analogical vtables and vptrs, but a little bit of boilerplate never caused me much grief.

Inheritance is much the same way. We can easily model that through composition, and at the internal workings of compilers it boils down to the same thing. Of course we lose type safety if we want to downcast, and there I'd say if you want to be downcasting at all, to please not use C for it because the things people do in C to emulate downcasting can be horrific from a type safety standpoint, but I'd rather people don't downcast at all. Type safety is something you can easily start to miss in C as the compiler provides so much leeway to interpret things as just bits and bytes, sacrificing the ability to catch would-be errors at compile-time, but some languages considered object-oriented aren't even statically typed.

So dunno, I think it's fine. Of course I wouldn't use C to try to create a large-scale codebase that conforms to SOLID principles, but it's not necessarily due to its short-comings in the object-oriented front. A lot of the features I would miss if I attempted to use C for such a purpose would be related to language features not directly considered a prerequisite for OOP such as strong type safety, destructors which are automatically invoked when objects go out of scope, operator overloading, templates/generics, and exception-handling. It's when I'm missing those ancillary features that I reach for C++.

  • 1
    I'm not sure how constructors could not be considered a prerequisite for OOP. Part of the basic essence of encapsulation is the ability to ensure invariants for an object. And that requires being able to properly initialize the object within those invariants. That requires a constructor: one or more functions, such that you cannot say that the object exists yet until at least one of them has been called. – Nicol Bolas Dec 19 '17 at 01:30
  • When we have information hiding with opaque types then the only way to instantiate them and copy/clone and destroy them is through the analogical equivalent of functions serving as constructors and destructors with just as much ability to maintain those invariants. It's just not directly modeled into the language and might resemble the form of `foo_create` and `foo_destroy` and `foo_clone`, e.g. –  Dec 19 '17 at 01:52
  • All we need to maintain invariants on `struct Foo` in such a case is to make sure its data members cannot be accessed and mutated by the outside world, which opaque types (declared but not defined to the outside world) give right away. It's arguably a stronger form of information hiding, on par with that of a `pimpl` in C++. –  Dec 19 '17 at 01:54
  • Yes, I know how people implement OOP in C, thank you. My point was that your statement that constructors are "not directly considered a prerequisite for OOP" is in error. – Nicol Bolas Dec 19 '17 at 01:57
  • I see, lemme correct that... but in that case might we say that C does provide (adequate?) support for destructors and constructors? –  Dec 19 '17 at 01:57
  • I agree with your `fopen/fclose` observations. Given that an “object” need only exhibit three primary and orthogonal characteristics — the classic ***state, behavior,** and **identity** triple* — the opaque `FILE *` pointers such as those returned by the libc *fopen(3)* function can be legitimately viewed as objects under any reasonable definition of that term. – tchrist Dec 21 '17 at 02:31
0

The distinction between an OO language and some other is not whether you can write a program a certain way (they're all turing complete, after all), but whether it comes with provisions to support this programming style.

In the end, everything in a program compiles down to machine code. By extension, that means you can write code for any programming paradigm in assembler. If you allow me to horribly simplify, C is basically a portable assembler. You can implement most programming styles in C (you may have to resort to macros for a few things, and it may not be as efficient as in assembler, but you can do it).

The difference between an object-oriented language like C++ and a procedural language like C is that you need to re-implement a lot of the provisions for object-oriented programming yourself that come built into C++.

If you use C, you need to manually define each implementation function, the virtual method dispatch tables for each class and subclass, keep them in sync or wildly typecast between base and inherited classes (or just stay aware of which methods are from the base class and call them via a super member or a chain of super.super.super).

Also, C++ knows what an object is, and can detect nonsensical code that a C compiler looking at your re-implementation of everything wouldn't be able to tell. It won't just NULL-initialize a missing function pointer at the end of the vtable and move on, it will tell you that you forgot to implement a pure virtual method, or will fill it in itself because it sees it was added to the base class.

Moreover, an OO language constitutes a standard for OO provisions. Your OO-with-C-code will be different from someone else's. If it's built into the language, you can just grab someone else's OO code and use it. If you use different styles for OO-with-C, you may have to create adapter objects.

uliwitness
  • 251
  • 2
  • 6
-1

Not a bad question.

If you are going to call c an OO language you would need to called just about all procedural languages OO too. So it would make the term meaningless. c has no language support for OO. If has structs, but structs are types no classes.

Actually c doesn't have a lot of features at all compared to most languages. It's mostly use for it's speed, simplicity, popularity and support including tons of libraries.

Glen P
  • 99
  • 2