Get the top HN stories in your inbox every day.
vaughan
gpderetta
I completely agree with this. When designing classes it is very easy to get carried away and incrementally add bits to the class instead of passing dependencies explicitly.
Arguably even config is too much and generally functions should only take the subset of config.
In the end this is more art than engineering: classes allow encapsulating all state that needs to be used by all functions together; but as you start making exceptions you'll end up with the mess you describe. The art is finding the right balance between what goes in a class and what should be a standalone (possibly generic) function. Personally, I'm still far from mastering that art.
Alexander Stepanov has a lot to say about this.
vaughan
There is definitely an art to it at some point, but I see a lack of tools to be a big problem.
We are in the stone-age of programming at the moment.
I think the solution is visualization.
I want to click on any variable, and see its full data-dependency graph. All the functions it flowed through and all the transformations that occurred all the way back to a single source of truth.
With this in hand, I think it would be much easier to understand how to group methods and state. We should write code such that this data-dependency graph is easily understood by humans.
tmcb
> OO is not a natural way of programming.
That is quite a bold claim. Can we define what is a "natural" way of programming? From my experience you are exposed to one or many programming paradigms and then, when required, you pick the one that works best for you, your problem or your team.
I still see value in modeling some particular problems with OOP and let the underlying model do the heavy-lifting. I know that under the hood every `subject.action(object)` has it corresponding `mangled_action(subject, object)`.
By the way, in our culture, the first exposure we have to functions as children is through infix operations: +, -, *, /. I would not say it is "natural". Prefix and postix operations are not "natural" either. You pick which one works best for you.
vaughan
I guess I mean that it's not the first thing people reach for unless they know about it. They have some data and want to write a function to do something.
But yeh its probably a too broad statement not worth debating on definitions.
1bent
OOP has always felt to me like it was inspired by writing GUI APIs; Sun's Suntools -> Sunview -> xview (if I'm remembering the names right) were early-mid 1980s C, and felt beautifully OO, and very clean to write GUI programs. I enjoyed writing image analysis and manipulation in them. Never used the successor "intrinsics-based" Motif and CDE, the code was yucky. Didn't write another GUI until I did a dashboard (for automated software deployment) in TCL/Tk. But yeah, C++ never interested me for OO, C was fine.
jupp0r
It's weird that so much of OOP back then was centered around deep class inheritance hierarchies as a means to share code when my favorite more modern languages (Rust and Go) intentionally leave out this part of OOP (thankfully, imho).
An eye opener in respect to this was Sean Parent's excellent talk "Inheritance Is The Base Class of Evil" at GoingNative 2013 [1].
rramadass
I really don't get why people keep repeating "class inheritance hierarchies are bad". If one understands Implementation vs. Interface inheritance and the intent behind each (the former strongly couples the code while the latter does not) then one can judiciously use inheritance techniques correctly.
I recommend a study of Bertrand Meyer's OOSC2 and language Eiffel - https://en.wikipedia.org/wiki/Object-Oriented_Software_Const...
Fire-Dragon-DoL
The reason is implicit makes really easy to miss things and the majority of software devs have very poor understanding of coupling. Consequence is if inheritance is a thing, you'll see monsters in the code.
If inheritance is not available, the problem doesn't exist.
Same goes for immutability, in the end our tools are tuning for the lowest performers
rramadass
Not true.
The basic idea behind "Inheritance" is simple and can be understood by all programmers. Its realization through various language features and their combinations is what makes it somewhat confusing. Once explained and practiced with discipline, inheritance is very powerful.
See my other comment: https://news.ycombinator.com/item?id=36428689
jupp0r
The ability to reason about code as you are reading it is not only important to "lowest performers".
gyrovorbis
It's just the latest hipster language trend. When OO was new, structural C was evil. When functional programming happened, everything before that was evil...
Because, yes, sharing state among classes for code reuse, is fundamentally evil... How dare you want to couple state and logic?
Almost like every single UI framework in every mainstream language has converged upon OO as the best way to model the problem at hand... GTk even invented a similar type system to what was mentioned in this PDF just to give C OOP constructs... Now witness as the Rust language has failed to produce a compelling UI/widgeting framework or paradigm, and the best ones out there are Qt-based or GTk-bindings (letting C hilariously handle the OOP for Rust).
rramadass
>It's just the latest hipster language trend. When OO was new, structural C was evil. When functional programming happened, everything before that was evil...
Right.
By any measure OOD/OOP has been enormously successful in the real world and hence it is annoying to see blanket statements like "OOD/OOP/Inheritance/etc. is bad" on HN (i expected better). It is one thing to discuss cautions/caveats/different approaches but to dismiss the whole thing is quite silly. Hence my attempt at edification of the readers :-)
DarkNova6
I think inheritance is the most convenient thing which came out of OOP, but interfaces are the most valuable one.
At least for business applications, you want to keep your behaviour and state separate. And people following OOP dogmatically will (ab)use encapsulation for use-cases where your data should be transparent.
Contrast this to interfaces, which are essentially composable specifications on code-level (and I absolutely love that Java uses interfaces to describe anonymous classes due to the power it gives you for documentation and specification).
rramadass
You might find Program Development in Java: Abstraction, Specification, and Object-Oriented Design by Barbara Liskov with John Guttag interesting.
jupp0r
The way I'm thinking about it (just a different expression of the exact same thought) is that inheritance as a means to share code is bad, while inheritance as a means to leverage polymorphism is good. Polymorphic classes can still share code, but this should be done using composition.
rramadass
> inheritance as a means to share code is bad,
Not necessarily; if they are strongly coupled related concepts within the same module then it is perfectly fine (eg. private inheritance in C++). Here you are basically structuring for code reuse and not is-a relationship.
>inheritance as a means to leverage polymorphism is good.
This is the "standard" idea of inheritance i.e. sub-typing using Liskov Substitution Principle.
> Polymorphic classes can still share code, but this should be done using composition.
Not necessarily as a combination of the above two should make clear.
mikro2nd
OOP was never "centered around deep class inheritance hierarchies". It was centred around message passing and dynamic method dispatch. The only significance of inheritance is to resolve the receiver of a message.
I feel strongly that most of the people who think OOP was bad are people who have only ever experienced C++/C#/Java or some even weaker instantiation of OOP.
What do you suppose you're writing when you implement a (micro)service? It's nothing different than an object -- some implementation whose details you don't need to care about when you use it, which details can be changed at any time without disturbing clients (modulo idiocy), and an interface that you use to communicate with it via messages.
And don't even get me started on the OO vs. Functional nonsense...
gpderetta
Simula67, arguably the first OO language, was centered around inheritance.
The other early major OO language was obviously Smalltalk which focused on message passing.
Both C++ and Java were majorly influenced by Simula, while more dynamic languages take on aspects of Smalltalk.
pjmlp
Java is clearly influenced by Objective-C and Smalltalk in semantics.
Not only their authors are on the record saying so, Java EE is inspired in an Objective-C framework (Distributed Objects Everywhere), and Hotspot is the evolution of Strongtalk JIT.
Kamq
Yeah, that still weirds me out. Especially considering the other obvious mechanism of code reuse, the function.
jupp0r
State can also be shared and reused together with functions operating on it - via composition.
Kamq
Sure, but that's desirable with, maybe, 5% of the code re-use opportunities I run across.
I'm not saying to never use classes. I just got really confused about them being pushed as one of the dominant forms of code-reuse.
lelanthran
> modern languages (Rust and Go) intentionally leave out this part of OOP (thankfully, imho).
Why thankfully?
Some solutions are a natural fit for a class hierarchy. Having to hack in workarounds using traits or receivers is, like any band-aid, ugly as hell.
gyrovorbis
"Thankfully" he says.
Now witness as Rust struggles to produce a compelling widgeting environment that isn't Qt or GTk bindings to other languages which support OO constructs. Witness as apparently creating a "Rust-friendly" OO paradigm or framework is an ongoing academic endeavor, because of this...
Believe it or not, for some domains, object-orientation is the right tool for the job... as some problems are just inherently modeled better with such a paradigm, and are able to take advantage of what it has to offer (encapsulation, polymorphism, inheritance).
jupp0r
There's a sizable chunk of people who think that the concept of inheritance for code sharing is causing more harm than good overall. These languages make it hard to do inheritance for exactly that reason.
lelanthran
> There's a sizable chunk of people who think that the concept of inheritance for code sharing is causing more harm than good overall.
Maybe. What I've seen online is that there is a sizable chunk of people who think that the concept of inheritance is causing more harm than good overall. I don't see many adding the qualifier "for code sharing".
> These languages make it hard to do inheritance for exactly that reason.
It makes those languages a poor fit for some problem domains, like GUIs, for example. Or games. Or many enterprise systems.
Which is why I am wondering why someone would be thankful that creating programs in certain very popular domains was made more difficult than the alternatives.
nielsbot
If you find this kind of stuff interesting, definitely take a look at this paper by Ian Piumarta:
https://www.piumarta.com/software/id-objmodel/objmodel2.pdf
An OOP object model you can implement in C where the model is open and extensible inside the user environment. It's a very minimal yet flexible system.
gyrovorbis
Reminds me a lot of the magic that is the Objective-C runtime. Fantastic paper. Thanks for sharing.
chmaynard
This reminds me of a course I took at Stanford around 1991. The course title was UNIX C Programming and the instructor was Dr. Eric Roberts. The programming part was to build a library of simple tools and the UI was the command-line. We didn't call it object-oriented but it involved programming with ADTs that had well-defined APIs.
Tomis02
As far as I can tell, the author says that "ANSI-C is a full-scale object-oriented language" in a slightly sarcastic tone, as there's nothing particular to OOP languages that you can't do in C. But I've heard many people say (and mean it) they do OOP in C.
I find it a bit dubious to claim you're doing OOP in C, considering that C does not have objects. And I find it twice as dubious because you can translate any FP/OOP code to procedural C; at this rate, you can start claiming that your x86 binary is OOP.
I often hear that "FILE is an object, it's exactly as if C++ had class FILE {...}, the class is just syntactic sugar, the result of the compilation is identical".
This is false, as it's not "just syntactic sugar". A C++ class binds a function to a specific struct, and the function can "belong" to no other struct. When doing OOP you have to choose - function F belongs to either object A or to object B. It can't belong to both. Which is why OOP has endlessly silly discussions about whether class Car should Turn() the class Wheel, or should the class Wheel Turn() class Car. Or should we refactor it into class SteeringWheel that will Turn() both Car and Wheel.
This is not a thing in C. Linus Torvalds can add a function F that operates on the internals of both FILE and DIR at the same time, for example, and suddenly it's less clear who "owns" F and which one is the object.
Which is why, personally, I don't think doing dynamic dispatch with void* in C can be qualified as OOP, it's just a pattern that's been there ever since the language was introduced. It's only after you add specific OOP features to the language that it devolves into an OOP language.
lelanthran
I'm not sure I understand the reasoning here. It seems to me that you have it the wrong way around, so maybe I'm missing something really obvious:
> This is not a thing in C. Linus Torvalds can add a function F that operates on the internals of both FILE and DIR at the same time, for example, and suddenly it's less clear who "owns" F and which one is the object.
In this respect C is strongly-typed and you will most definitely see compilation errors if `void F(FILE *fp)` is called as `DIR *dp; F(dp)`. If you want to make a function F that operates on both `FILE` and `DIR` types, you have to bypass the type checks explicitly! IOW, it is always clear to the reader of the code that F can take either a `FILE` or a `DIR`, or only a `FILE` or only a `DIR`. There is never any ambiguity to the reader.
OTOH, with C++ ...
> A C++ class binds a function to a specific struct, and the function can "belong" to no other struct.
Unlike C above, this is never clear to the reader of the code though. For example, looping over an array of instances calling `.F()` on each instance: the reader cannot know which implementation of `F` is being invoked.
It's literally impossible to tell just by looking at the loop. Sometimes it's impossible to tell even by examining all the code because the specific method that is bound to an instance may only be determined at runtime.
gpderetta
This is C++:
for (auto&& x: collection)
x.foo();
You say you have no idea what foo is.This is C:
for (int i = 0; i < collection_size; i++)
foo(collection[i]);
Now you say that which foo is being called is very obvious...... but [1]:
#define foo(x) x.foo(&x)
x.foo is a function pointer and someone has been implementing OO in C (far fetched? it is literally the title of the article). With C++ at least if I M-. on foo emacs will show me all possible targets (or directly take me to foo implementation if not polymorphic); With C, good luck teaching your IDE your custom flavor of OO [2].So, no, C and C++ are more similar than you think. The biggest difference is the presence of overloading which, in the static dispatch case, makes resolving the actual function from the function name slightly harder in C++ without tool help. Overloading has little to do with OO, although it is a form of static polymorphism.
In the dynamic case they are equivalent (well except for the fact that you have to build the vtables by hand in C and the syntax is a bit awkward.
[1] yes, yes, arguments are not protected against multiple evaluation. Sue me.
[2] with emacs of course this is actually possible, just merely hard.
Tomis02
To be honest I don't understand your comment, I think you're talking about something else, so I'll try to rephrase.
My point is that C is not an OOPL. There's two aspects of OOP: 1) the concrete language features 2) a pseudo-philosophical wishy-washy hippie territory where nothing is clear and everything is subjective, where you view all problems as something that is to be modelled with objects, and your own mental model is firmly centred around objects.
Since C lacks concrete OOP features, I will proceed to show why the latter aspect (philosophical OOP) is problematic.
In OOP, objects are entities composed of data and functions that operate on that data. That's what C++ classes usually are: members and methods bound syntactically together. OOP doesn't allow a method to belong to two objects, by definition and by C++ syntax.
Now, let's say you have a C API that offers 2 structs, A and B, and some functions F1A(A, ...), F1B(B, ...), and so on. The people who claim C is OOP language will say "a-ha! A is an object. The data (encapsulated too!) is in type A, and the functions F1A, F2A, ... are the methods. You could write a C++ class 'class A { private: data; public: F1A(...);...};'. Same for B. See? A and B are objects!"
This is the philosophical OOP in action, where "it looks like OOP" becomes "is OOP".
So what happens if the API adds a new function, FAB(A, B, ...), that operates on the internals of A and B? If we switch back to OOP parlance, if you had two classes, A and B, and wanted to add FAB to one of them, which class would FAB belong to?
Well, it's problematic because we're dealing with imaginary objects, so the answer can be whatever you want it to be.
You can arbitrarily say "pick the first parameter type to be the object that owns FAB". Well, what if it's FAB(const char*, A, B)? And even if A is the first one, doesn't FAB changing B break the all-precious object encapsulation? Once you introduce FAB, are these objects at all?
The problem of choosing the "owner" is a common one in C++ OOP because the objects are real (there's syntax to mark something as an object), whereas in C the objects are imaginary and, therefore, a fuzzy ambiguous concept. If you take the set of all functions whose 1st parameter is an int, does that form an object? If everything is an object, is anything an object?
But, like I said, this tends to be a non-problem in C (if you're not a OOP person) because you'll recognise that FAB(A,B) does something useful, and all this conceptual objects design is just noise that does not matter and you're happy to say "my code is not OOP but it does something useful in the best possible way".
Which is why I think that philosophical OOP (object thinking) is dubious, and the only way you can call a language OOP is if it has OOP features. Otherwise, if the only thing you're doing is applying your OOP mindset, I don't think it's fair to say that the language itself is OOP.
G3rn0ti
OOP is essentially a software architecture model. You can use this architecture in any language with a bit of discipline even if it does not give you all syntactical safety guarantees. At some point even object oriented assembler was a thing (as assembly routines may very well receive an address pointing to an object).
rramadass
> OOP is essentially a software architecture model.
Finally! Somebody pointed this out.
OOP is merely a different way of structuring "Procedural/Imperative" programming. In the early days of OOP hype, the greats like Edsger Dijkstra, Niklaus Wirth were rather critical of it and denied that it was something very "Original". It was correctly pointed out as merely a technique for structuring code for "programming in the large". Once you understand this you can design and use OOP (for a specific definition) in any language.
kallistisoft
You can absolutely translate object oriented C++ to vanilla C. As a young teenager I would routinely convert C++ from books I got from my parents/library to C, because I didn't have access to a C++ compiler. The process isn't that difficult....
Take the members of the C++ object and create a struct to hold the data then create a 'constructor' function for populating that data. Afterwards you just call the member functions of the original class, as simple C functions, and pass the struct as the first argument.
This in fact is what the actually happens at the assembly level when using a C++ compiler! The idea of an 'object' is purely an abstraction!
ameminator
However, one CAN do "object-oriented" programming in C. There are ways of modeling what a piece of data is (a struct with its members). There are ways of modeling how a piece of data can behave (functions operating on those structs/pointers to structs). Perhaps this is lacking in features and expressiveness compared to OOP-first languages like C#, C++ and others, but object-oriented concepts can apply in C - look to the compiler to organize private, public functions and ownership.
Tomis02
I agree that you can _imagine_ that FILE and DIR are objects, you can imagine they have behaviour, you can apply your OOP mental model to procedural code.
But it all breaks down the moment you add a function that operates on the internals of both FILE and DIR, because this function doesn't belong to any one object. And if you don't notice it, you keep thinking FILE and DIR are objects, when in fact they're not (a method can't "belong" to two objects, at least as far as objects are perceived in the software world).
In short, I can agree that it's possible to write C with a OOP mindset. But (let's call it) imaginary OOP may not be actual OOP (as when enforced by the C++ compiler).
gpderetta
In an OO model, you can implement exactly that by having FILE and DIR derive from a common base class, then you can have your function take such a base and either act on the common subset or do a type query and cast to the derived type as needed (this is usually frowned on, but not uncommon).
But yes, of course shoving everything under OO is bad. A bit of OO should be a mean to an end, not a inflexible design principle.
skissane
> This is not a thing in C. Linus Torvalds can add a function F that operates on the internals of both FILE and DIR at the same time, for example, and suddenly it's less clear who "owns" F and which one is the object.
It isn’t a thing in a C++ either if one makes all the fields public or if one uses friend.
Member accessibility is not essential to the idea of OOP, since there are OOP languages which don’t have it, or in which it is merely a convention, or something which can be overridden-and a person can use an OOP language which has it yet fail to use it.
So, I don’t think “C lacks private members” is a good argument against C being “OOP”. Especially when C actually has the moral equivalent of “private” given APIs can be based on opaque pointers, so your compilation unit has no idea what the fields or layout of some structure controlled by another is.
Tomis02
> It isn’t a thing in a C++
But it is a thing in OOP. That's the point. C++ is multiparadigm. All the OOP gurus will tell you that objects shouldn't expose their internal data, only methods.
That's why the so-called encapsulation is constantly brought up. People telling you C is OOP will say "FILE is an object, the FILE struct + fopen/fclose/fwrite constitute an object, FILE is opaque, we can only interact with its internals through the public methods". "DIR is an object, ...". And so on.
And the problem is that when the Linux C API exposes a function that takes both a FILE and a DIR, and operates on both their internals, your whole idea of OOP-ness shatters because a method can only belong to a single object, by definition.
skissane
> And the problem is that when the Linux C API exposes a function that takes both a FILE and a DIR, and operates on both their internals, your whole idea of OOP-ness shatters because a method can only belong to a single object, by definition.
You can do the same in Smalltalk though-create a utility class containing a method which operates on one instance of each class, and create accessors to expose all their internals. If the ability to do that means C isn’t an OO language, then Smalltalk isn’t an OO language either. And if Smalltalk isn’t an OO language, then OO languages don’t exist.
aninteger
And for people who took this to the "next level" just look at GTK.
pjmlp
That would have been Motif and CDE, which Gtk is based on as idea.
jandrese
No seriously, the GTK C bindings are basically written in a half-formed version of the old C++ "C with preprocessor macros" syntax.
It looks like this when you program it:
GtkWidget* grid = gtk_grid_new();
GtkWidget* label = gtk_label_new("Hello World");
gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
That GTK_GRID bit is a macro that evaluates at runtime and will chuck out runtime errors if the widget doesn't match. It supports inheritance. If you have for example a gtk_combo_box_text, you can use gtk_combo_box_set_active(GTK_COMBO_BOX(my_combo_box_text), 0) and it will select the first entry in the gtk_combo_box_text because gtk_combo_box_text inherits from gtk_combo_box like any good object oriented system.dfox
Motif/libxm is very similar to that. With two important exceptions: the user code does not use type-checking macros and “stringly-typed” API for set a property to something is more or less a part of the overall ecosystem (well, Xm is just an layer built on top of Xt).
Gtk+ was originally an implementation of whatever parts of Motif were used by Gimp, built on an underlying object model that has nothing to do with Xt (which has both good and bad implications).
gyrovorbis
I'm a huge academic fan of what GTk has accomplished (thanks to their GObject type system), and as much as I know the C89 crowd who thinks macros are all evil probably abhor this kind of thing, I think GTk is one of the most epic, impressive, ambitious C codebases in existence. Witness as non-OO C matches, rivals, and quite often beats Qt on equivalent classes/features in plain C... It's even above "just C++ style C," as they have added features like a property and signal system...
I'm such a fanboy it inspired my own type system and massive core library, libgimbal, which uses a type system similar to GObject and targets game consoles like the Sega Dreamcast: https://github.com/gyrovorbis/libgimbal.
reidacdc
I remember writing a GTK extension widget many years ago, and yes, it was very much like this. The macros end up making your very own hand-coded vtable-equivalent, so that function calls get dispatched to the appropriate point in the inheritance chain. It was pretty eye-opening!
undefined
gyrovorbis
Exactly. Amen. GTk is the shining proudest most epic achievement of object-oriented C programming, and they still enjoy massive benefits in terms of being able to interop with every language ever because of this approach.
pixelfarmer
The Linux kernel contains a lot of C OOP, similar to GTK and other such frameworks.
As soon as you need bindings done during runtime, you will end up with structs containing function pointers as some sort of interface descriptor, and potentially that is embedded or aligned with structs containing data. This is at least OOP class level functions with data they can operate on and if you allocate the "ops" struct (together with data) as well we are talking actual object instances. The Linux kernel is full of such things, plus there are even macros to cast up/down the inheritance tree.
moth-fuzz
One thing that's bothered me for a few years about Object-Oriented code, is the question of why the dichotomy of 'implementation' vs 'interface' is drawn on the exact same line as 'variables' and 'functions'.
Everyone who's ever worked in a functional programming languages knows that functions can easily be considered 'state', and everybody who's spent time in real-life plugging in various electronic devices knows that data itself can be considered an 'interface'.
So why does OOP dogma conflate these ideas together? Why couldn't a single variable or property be virtual and polymorphic? Why couldn't a member method be reassignable like a member variable? The philosophy and the actual implementations just self-reference each other. Interfaces are great because they keep interfaces separate from state. I agree. But strictly in terms of language features, why are functions considered interface while variables are considered state? Well, because that's just how they're defined, I guess.
But if you're doing OOP in C, and you have a VTABLE full of pointers, well, it doesn't really matter what those pointers point do, do they? They could be function pointers, they could be variables/memory locations, they could even be references to other structs. It's not quite as delineated when you do it from the bottom up.
rramadass
Not quite sure what you are trying to say here; but ...
> the dichotomy of 'implementation' vs 'interface' is drawn on the exact same line as 'variables' and 'functions'.
That's not true; They are orthogonal to each other.
OOP is just a way of structuring Procedural/Imperative programming; "variables" maintain state while "functions" change/read state. You are just bundling them together to gain fine-grained modularity. An "interface" is anything (i.e. can be both variables and functions) which is "publicly" accessible by a client. An "implementation" is conversely not accessible by the client (i.e. encapsulated) but can also consist of "variables" and "functions".
> Why couldn't a single variable or property be virtual and polymorphic?
Not sure what you mean here but you do have tagged unions/variants/sum types which gives you what you maybe looking for.
> Why couldn't a member method be reassignable like a member variable?
It is possible in certain object models. Lookup "Metaclasses" in your favourite language for possible support. If you want to see example code in C++, checkout the classic Advanced C++ Programming Styles and Idioms by James Coplien. The book contains lots of examples of mind-bending OO trickery using C++.
gyrovorbis
This book is an absolute classic. I came from C++20, using concepts and constraints, doing a lot of compile-time metaprogramming and shenanigans, and I set off on a quest to rewrite a lot of my core tech stack in plain ol' C ('17 revision) for language interoperability reasons...
...and I literally almost gave up on being a C programmer because of bashing my head against language limitations... This book completely and totally changed everything and is the reason I completed this very ambitious project (https://github.com/gyrovorbis/libgimbal)... It's not just good for object-oriented C, but also for approaching the C language differently in general. For pushing its boundaries rather than accepting its limitations.
Anyway, this "PDF" was such an inspiration on me as a C programmer that I managed to track down a physical copy on Ebay. lol.
edgyquant
I went through an “OOP in C” phase when I first got into C years ago. This stack overflow[1] helped a lot as well
1. https://stackoverflow.com/questions/351733/how-would-one-wri...
alfiedotwtf
Can't find the link now, but there was some malware recently (maybe under 3 years ago) that was found to directly use this book as a basis for their code.
Get the top HN stories in your inbox every day.
I've actually started preferring the `action(subject, object)` form of programming which OO in C entails, rather than `subject.action(object)`. The latter is certainly easier for discovery via auto-complete (with most current tooling).
OO is not a natural way of programming. Everything always starts simply with functions that take arguments. Then you have a function that calls another function with some of the old arguments and some new ones.
Most people go: let's make the shared param an instance var.
becomes... The problem with a class, is that every method of the class potentially depends on every other member of the class. What usually happens is that stuff is added to the class that doesn't make sense. And every class needs a noun to name it. Then you have to think what is the proper name for this abstract thing you don't even know what it is yet. Which leads to all these quirky class names that are unnecessary.If you are explicit about what data dependencies each function has, it becomes easier to see the commonality that should be extracted into classes. Most people just shove everything in a class too soon. And most languages push you to use classes and methods...which usually look very different to how functions are represented.