2

My first introduction to programming was Java, which was horrible so I learnt Actionscript3 which was nice... "The point is" OOP was my introduction to programming where by I went on to gain a career in PHP and while I can confidently write programs/scripts in imperative languages I am no where near as comfortable in doing so.

The primary reason is because I am unable to understand how imperative/procedural languages can be extended in the same way OOP languages use polymorphism and substitution.

I am now looking to learn additional languages and may even have a crack at C, only if I can work out the basic principles for substituting functionality.

Can anyone explain the basic principles used to extend the functionality of a library/function without re-writing that entire function. Because in OOP you would override one method of a class and possibly call the super method to retain some of the original behavior.

Flosculus
  • 183
  • 8
  • possible duplicate of [What were the Design Patterns of the procedural programming era?](http://programmers.stackexchange.com/questions/201880/what-were-the-design-patterns-of-the-procedural-programming-era) – gnat Oct 31 '14 at 15:48
  • ...see also: [Aren't structured programming and object oriented programming complementary?](http://programmers.stackexchange.com/a/200635/31260) – gnat Oct 31 '14 at 15:48
  • 1
    @gnat I read over those, and they are interesting. But I am trying to find out what the equivalent for inheritance is in non-OOP languages. Those links don't really explain that. – Flosculus Oct 31 '14 at 16:25
  • question title suggests that it's [broader](http://meta.programmers.stackexchange.com/questions/6483/why-was-my-question-closed-or-down-voted/6490#6490) than that. Not to mention that it doesn't use tag [tag:inheritance] – gnat Oct 31 '14 at 16:27
  • I have made alterations, if they are still incorrect, feel free to alter them. – Flosculus Oct 31 '14 at 16:33
  • I think you're looking for a solution (inheritence) to an undefined problem. Giving a concrete example might help. What is the problem that you would solve in an OO language with inheritance that you can't solve in an imperitive language? – bunglestink Oct 31 '14 at 16:39
  • 1
    not bad, edited question doesn't look like a duplicate anymore. By the way, since you mentioned C, are you aware of [function pointers and how these work](http://stackoverflow.com/a/840703/839601 "explained eg here")? – gnat Oct 31 '14 at 16:45
  • 1
    There's some minor conceptual problems here, because you most mainstream OOP programming languages (including Java) conflate abstract data types with objects and because inheritance is not an essential feature of OOP. Despite common parlance, Java `class`es are *not* objects, they're abstract data types. C can do abstract data types easily enough with opaque structs. Instances of Java `interface`s are objects (in the OOP sense), and there's no safe way of implementing them in C, because C doesn't have closures. So you can make a struct of function pointers, but you have nowhere to put... – Doval Oct 31 '14 at 17:04
  • 1
    ...instance variables, unless you add a single `void` pointer to the struct which points to where the instance data is, but then you have to cast to get the data and risk undefined behavior. – Doval Oct 31 '14 at 17:05
  • @Doval I think that puts my problem in better words. But I don't want to learn to 'emulate' a paradigm I am accustomed to. I want to learn the techniques used to handle scalability of large applications. I read the Linux Kernel source sometimes out of curiosity, and I can't work out how they organize the common interfaces of multiple drivers. And by interfaces I do mean interfaces if written in OOP, as in `public interface DeviceDriver` if such a thing existed in C. – Flosculus Oct 31 '14 at 17:11
  • 1
    Actually, the modern Linux Device Driver Model, which was introduced about 10-15 years ago, I think, *is* maybe not purely object-oriented but heavily based on OO ideas. It's not coincidence that the central `struct` which holds it all together is called `kobject`. – Jörg W Mittag Oct 31 '14 at 17:26
  • 1
    @Flosculus You're probably better off reading up on functional programming. Side effects don't scale well; to make sense of any given part of the program you need to understand everything that occurred before that point as well. How to best avoid side effects and mutable state while still getting useful things done is still a subject of much debate and ongoing research, but it's clear that less side effects makes things simpler to reason about by virtue of being able to reason about parts of a program in isolation. In any case, C isn't a good language for large programs. – Doval Oct 31 '14 at 17:54
  • 1
    I would recommend to consider [edit]ing the question to focus on a specific procedural language you're most interested in. As written now, it may read as inviting a list of answers addressing all procedural languages out there, which is [probably not a very good idea](http://meta.stackexchange.com/tags/list-questions/info "as explained eg here") – gnat Oct 31 '14 at 18:19
  • Please note that "OOP" is a subset of "imperative programming", so I think your question is imprecise. Also, I'm confused: you say "inheritance", but I suspect your question is about *code reuse* and/or *polymorphism* and/or *subtyping*. Is that so? Because there are many ways to reuse code outside OOP. (In other words: you're looking for a way to do inheritance. **Why? What actual problem do you hope to solve with inheritance?**) – Andres F. Nov 29 '14 at 16:05

3 Answers3

6

If you want a good example of full-fledged OOP in C, take a look at GTK+. Mostly, your constructors have a lot of boilerplate to initialize things like vtables and keep track of a type hierarchy. Creating your own object for GTK+ is a good way to learn what most OO languages do for you behind the scenes.

One thing you'll learn by writing some real code is that virtual methods are not as common or necessary as you would think they'd be. Programmers have a tendency to overuse inheritance. Most of the time, you know exactly which static function you need to call, and you're just sharing a simple data structure between several different functions. You extend it simply by creating a new function that works on the same data structure. This is how the vast majority of procedural code works.

When you do truly need virtual methods, you just add function pointers to that data structure you pass around. Then perhaps create a wrapper function to encapsulate the ugly function pointer syntax. See here for an example of how that's done in GObject, the object library of GTK.

If you need to potentially add fields, that data structure you pass around typically has a void* or something where you can store implementation-specific data.

Again, write a real app in GTK+ as a learning exercise, and I think you'll find the patterns somewhat familiar, once you get past the syntax.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479
  • "You extend it simply by creating a new function that works on the same data structure." I figure that underneath, that is what always happens regardless of paradigm. Thanks, this makes it clearer to me. – Flosculus Nov 03 '14 at 10:26
1

I think the easiest way to understand this is by looking at a simple example in C: the qsort function of the standard C library. As a user of that lib, you can provide an arbitrary comparison function to qsort here without touching or recompiling the library.

Another good example was shown in this former SO post. It exaplains how to build the equivalent of a String class in C, and how to emulate inheritance.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
0

This recent blog post by Bob Martin is relevant. In it, he defines providing convenient ways to implement polymorphism as being the essential element of what makes a language object-oriented.

In light of this, we can read your question as "how do I do object-oriented programing in a non object-oriented language?" The answer to this is quite simple: you don't if you can possibly help it. Yes, it is possible to implement it in many such languages, but the results are always unpleasant and difficult to read or work with. If your problem involves the need to handle different types of data in similar ways (i.e. if it is essentially a polymorphic problem) then use an object oriented language. If you have to work in a non-oo language, try to unify your data such that you never need to handle different types at the same place in your code. Learn to worry less about repeating yourself: it's much harder to avoid in non-oo code. And use function pointers as a last resort, when you absolutely need them only.

Jules
  • 17,614
  • 2
  • 33
  • 63
  • The more I read Uncle Bob's posts, the less I respect him. The guy has no idea whatsoever about what FP is. No shame in that; there's plenty I don't know either, but I least I try not to rant about it as if I did. Examples of things he gets wrong: he speaks of polymorphism as if naturally belonged to OOP or FP didn't use it (wrong), he ignores higher-order functions as the natural way to do what he calls "source inversion", "too many parenthesis" is not something found in FP (maybe he got confused with Lisp?), "true functional programming has no assignment" (oversimplification), etc. – Andres F. Nov 29 '14 at 16:17
  • It drives me mad that Uncle Bob feels confident enough to write about the differences/similarities between OOP and FP when he clearly is familiar with only one of the two! – Andres F. Nov 29 '14 at 16:21
  • 1
    I can't really comment on the FP aspects of the article, as my functional experience is rather limited, but from the limited perspective of defining what the critical core of OOP is, I think the article's spot on. – Jules Nov 29 '14 at 16:47
  • I just found [the talk which has the slide](http://www.slideshare.net/ScottWlaschin/fp-patterns-buildstufflt) Uncle Bob was ranting against. It's interesting. If I were a software engineering guru and published author like Uncle Bob, I would have taken the effort to find the talk and see what it has to say. Maybe, just maybe, he's just mistaken about FP because he's unfamiliar about it. But he gives no indication in his post he did so, which doesn't surprise me... – Andres F. Nov 30 '14 at 18:07