In practice, i'm not seeing this. In that procedural example, you can pass in any input you'd like. Suppose the function in that example accepts an array. Now, inside the function, I have to devote a non-trivial amount of effort to determine if the array contains the type of data I'm expecting. And if I want that function to change the array for possible use later, I'll need it to return the array and I'll have to store that return.
Now, that array, implemented as an Object, is structured. Strongly typed. Even private properties with setters to enforce consistency.
And that procedure, implemented as a method on that object, needs none of the consistency and validation code at the top of the procedure. And it can make changes to the properties themselves without the need to pass around variables.
Sure, most of the benefit of OO is in the structure and organization it brings. But no, it's far more than, as you're making it sound, the compiler is passing around an implicit argument on your behalf.
The argument above is that most developers write object-oriented code in procedural languages. They have a set of functions that perform actions on a specific type of data structure. To encapsulate functionality and keep the codebase clean, all reads and writes to these data structures should go through these functions. This pattern is ubiquitous in well-written C code. OOP itself simply provides a standard framework and syntactic sugar to make this type of code more consistent and clear.
EDIT: Here's a real-world example: (came up for the first search of hash.c) http://www.ks.uiuc.edu/Research/vmd/doxygen/hash_8c-source.h...
Suppose i have 2 properties in my class, 'start_date' and 'end_date'. They are private and have setters.
In a method that uses those 2 properties, I can trust that they are of the right type, that start_date is < end_date, that they represent a reasonable range based on my logic defined in the setters. All of this can be taken for granted.
In this procedural example, imagine some sort of hash or struct or associative array (whatever you want to call it in your given language) is supplied with those 2 keys.
The procedure cannot trust that the inputs are valid. It has to check everything. If you can rely on type safety, congrats, that's one less check. But there are plenty of others.
On one hand you have an option where you have to trust the developer will chain the appropriate method calls to build an unrelated data structure that gets passed-in to your target method.
On the other, you have the possibility that a developer will knowingly and willing subvert the encapsulation by writing directly to private variables while ignoring the business logic that's being enforced in the setters.
Do you mind me asking... what exactly are you arguing there? In the first example it's easier to do it wrong than it is to do it right. In the second example it's easier to do it right than it is to do it wrong -- in fact you have to specifically write to protected members to break it.
How are we still discussing this?
Well if you personally want to use a procedural language for OO development, that would explain a lot about this conversation.
Anyway, good talk. Appreciate the back and forth. I wouldn't hire somebody with a mindset like yours but I certainly like chatting on HN.
I agree with his point that the difference between OOP-style C and code written in an object-oriented language is language support. I have read some very OOP-style C, and it is extremely centered around chunks of data (objects.) The idea that code should be organized around data structures goes way back. The terminology in this Fred Brooks quote shows how old the idea is:
Show me your flowchart and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowchart; it'll be obvious.
In object-oriented C, it is even true that most functions are closely associated with a single structure, as if they are methods, though of course it isn't as cut and dried as it is in languages where that concept is rigidly enforced.
Possibly unrelated, but I've also seen procedural C that is verging on OO, showing an interesting state of evolution: pieces of data are implicitly grouped together, in that they always appear together in function signatures, but not grouped into structures. As a trivial example, if a point had x, y, and z coordinates in space, any function needing one of those coordinates would take all three throughout the entire codebase. Instead of
float altitude_difference(float p1_z, float p2_z);
you would see float altitude_difference(float p1_x, float p1_y, float p1_z,
float p2_x, float p2_y, float p2_z);
because points were regarded as aggregates that should be passed around together. This made it much simpler to remember function signatures, and it communicated the intent to treat certain chunks of data as aggregates. (I think this technique was used in Fortran before C even existed.) I imagine that from there it was a very short step to structs.Almost everything in the history of OO language features has boiled down to support for practices that were first developed and used without language support, often in C. If I remember correctly (remember reading, not being there) people attempted to differentiate between public and private data and methods in C (using macros and/or something similar to the the C++ pimpl trick.)