Bottles of OOP - https://news.ycombinator.com/item?id=12129821 - July 2016 (71 comments)
I'm very happy to see it out for Python!
Reading these two really helped me understand just how impoverished the concept of OOP has become by C++ and Java, from its Smalltalk roots.
I believe in mechanical empathy. I think developers should - win performance is a concern - think about how their code ends up on the CPU, what ends up on the heap, how caches are used, and so on.
But for most Python developers, and Ruby developers, it's more important, in more use cases, to have clear and readable code that is easily maintainable.
I've met Sandi, I've gone through her Ruby books, I recommend her teaching and her books to others. I don't see the problem.
If you need ASM, use ASM. If you're on a team doing OOP, maybe learn about OOP.
You can also look at any microbenchmark between pure Python and a native language of your choice, even one that uses GC like OCaml or Go, and unless the Python code has been written so that it spends all its time calling C code the way you sometimes can with regex-heavy code, Python will generally lose by a varying margin. These micro inefficiencies multiply at every level hundreds of times over to create needlessly slow, inefficient applications.
The truth is I can link benchmarks, case studies of app rewrites from Ruby to Go or something comparable, measurements about the results of using NIFs in Erlang/Elixir, etc. all day long but you'll ignore all of them.
The site says, "Available in digital form only (epub, kepub, mobi, pdf). Includes separate books for JavaScript, PHP, Python, and Ruby languages, and beer and milk beverages."
There is no mention of needing special software to read them, so I think it's safe to guess that there is no DRM. And it's sold directly by the author. Publishers are generally the ones who insist on DRM. It would not surprise me if there was watermarking, but that is not DRM.
And I would guess that likewise there are still a lot of people that don’t know this.
Also, sometimes one might not realize that the title got changed until it’s too late to edit the title of the post.
I've never really had the problem that I've read an OOP text and felt "this was too short".
That's all I got. Best of luck!
Code in any form can generate a ton of incidental complexity. The issue isn't the tool rather than the education to properly wield those tools. Especially when you introduce the team dynamic where everyone has varying understandings of what is being built and how it should be built.
Class Foo.__init__(self, db, blob_storage, secrets_manager, …)
Instead of class Foo(DB, BlobStorer, SecretsMgr)
Etc
For businesses, having a highly optimized web application that takes a long time to develop and doesn't allow for quick additions of new features is not worth the cost. Instead, they can have a poorly optimized web application with way more features and a faster feature production because Python/Ruby/Javascript are more approachable than other native languages.
And that "ton" is still miniscule compared to front-end development which almost completely eschews OOP and has 10x more incidental complexity.
I guess my point is that, while OOP's incidental complexity is large, it's still insignificant compared to other technology stacks which developers are showing a great appetite for anyway. Things like "incidental complexity" is irrelevant to developers anyway, today, at the tail end of 2024.
IOW, OOP introduces significantly less $BAD_THING, when the clear majority of developers don't even care about the quantity of $BAD_THING in the first place, making the whole "should we use OOP" argument moot.
Doesn't matter if you use it or not, the extra introduced incidental complexity is still going to be insignificant due to the complexity load of the entire project, more so in front-end.
Hence, there's no point in having the argument in the first place.
For a short intro to Sandi's style and approach, I always recommend this 35min talk: https://youtu.be/OMPfEXIlTVE?si=Ird6t8uDN86T06Y7
Aside from any specifically educational content, as a talk it is fantastic - funny, smart, well put together.
The main reason I see new devs opt for extends, is because that was 99% of the content in their Java 101 programming course, not because it exists in the language. Imagine how many more `friend`s we would have in cpp if that was crammed down everyone's throats? :)
I think you're confusing "OOP is used in projects and I've seen accidental complexity in projects" with "OOP generates accidental complexity".
The truth of the matter is that developers create complexity. It just so happens that the vast majority use OOP.
I challenge you to a) start by stating what you think OOP is, b) present any approach that does not use OOP and does not end up with the same problems, if not worse.
So you have to use composition.
The GoF book (the design patterns book) says in a page right near the start, "Prefer composition over inheritance", in the middle of an otherwise blank page, presumably to emphasize the importance of that advice.
As others have replied, composition is one technique you can use in OOP, not something that is the opposite of OOP.
You can also use composition in non-OOP procedural languages like C, by having a struct within a struct.
https://www.google.com/search?q=can+you+have+nested+structs+...
b) The best style is no style, or at least pick a more recently popular dogma like FP, at least it gets you easy/safe parallelism in exchange for throwing some of the tools out of your toolbox.
Meanwhile its creators can not hold the whole complexity in mind (often barely in spec) and still can produce a artifact that produces correct results.
I see you opt to go with a huge amount of handwaving over the question.
> Functions and structs.
That's what a class is, and thus OOP, except it supports information hiding and interfaces. So your alternative to OOP is... OOP?
Edit to add: Bottle's own FAQ says so: https://bottlepy.org/docs/dev/faq.html#what-about-flask
OP complained about accidental complexity, not subjective takes on how hard it is to refactor code.
Even so, anyone who has any cursory experience with TypeScript projects that follow a functional style can tell you without any doubt whatsoever that functional style is incomparably harder to refactor than any "enterprise-grade" OOP.
Compare e.g. to "What should a language have instead of Lua-like tables? Maps and vectors" — "But that's what a table is, so your alternative to tables is... tables?"
I'm not rabidly anti-OOP, but the point at which I turn against it is when the pursuit of "properly" modelling your domain with objects obscures the underlying logic. I feel like this book reaches that point. This is her stance on polymorphism:
> As an OO practitioner, when you see a conditional, the hairs on your neck should stand up. Its very presence ought to offend your sensibilities. You should feel entitled to send messages to objects, and look for a way to write code that allows you to do so. The above pattern means that objects are missing, and suggests that subsequent refactorings are needed to reveal them.
Absolutely not! You should not, as a rule, be replacing conditional statements with polymorphic dispatch. Polymorphism can be a useful tool for separating behaviour into modules, but that trade-off is only worthwhile when the original behaviour is too bloated to be legible as a unit. I don't see an awareness of that trade-off here. That's my problem.
Very helpful and clear thinking about refactoring out complexity—and not just refactoring for its own sake, but under the constraint that you want to move your program forward, add new functionality, etc. Refactoring with a direction, purpose, and direct payoff.
The biggest problem with accidental complexity _is_ how hard it is to refactor code. Refactoring code is a huge part of software development.
>> A. OOP as practically implemented for the last 25 years is glueing functions to state
> I see you opt to go with a huge amount of handwaving over the question.
I think the question was answered pretty clearly. You can't ask for an opinion ( "what do you think" ) and then criticize the response as 'hand-waving'.
I found the excerpt in the book and I don't see her mentioning traditional class-level polymorphism (of the Java kind) anywhere around it. What SM generally advocates for is using OBJECT hierarchies to implement behaviors and encapsulate logic, the objects usually being instances of simple (and final!) free-standing classes. All thanks to the ability of any Ruby object to send messages to (call methods of) a different object, without knowing or caring about its type or origin, and the other object supplying the behavior without having to check its own type (because the correct behavior is the only one that the object, being a specialized object, even knows). This is done at runtime and is called "composition" (as in "composition over inheritance") and is different from using pre-built CLASS hierarchies to implement behaviors, aka "inheritance" (as in "composition over inheritance"). In Ruby, composition is Dog.new(Woofing.new), whereas using inheritance (class hierarchies) is Dog.new after you've done "include Woofing" inside the class.
I don't know Python well, but it seems like the person in the top-level comment expressed their dislike for the second kind.
I had the same "this isn't realistic!" complaint when studying the book, but the examples nonetheless helped me see, practice, and adopt the techniques so that I could immediately apply them to the complex production examples I needed to improve. YMMV... but as a former skeptic, "trust the process." Walk that path an work those examples for 5 days, then see how you feel. I was already pretty skilled, including in complex refactorings, and it still leveled me up.
More seriously, HN should instead display an instruction after submitting, informing that the title was changed and that the submitter should check the change and edit if necessary. The issue is that most submitters either don’t seem to notice that the title changed or don’t hit on the idea that they can edit it after the fact.
You could say that I just did not do it right, but that is the problem. You need to know precisely what the future will want to do it right and that is never possible to know in advance. OOP encapsulation is heavily overrated. There are a ton of headaches in C++ that do not exist in C because C does not try to do these things. Ever hear of the diamond problem? It does not exist in C. Nonsensical types that span multiple lines when trying to figure out why there is a type error? Not an issue in C either.
C++ was advertised as reducing complexity, but in reality, it that encourages developers to drown themselves in complexity. If it were not for C never gaining a widespread STL equivalent, C++ would be far less popular. Sun Microsystems did make libuutil to provide such facilities, but sadly, it never caught on outside of Sun Microsystems technologies. The BSD sys/queue.h is the closest we have to it, but it is only for lists, and we need trees too to get a good equivalent to the C++ STL. That said, libuutil is available through ZFS, so it is not that people cannot adopt its awesome AVL tree implementation on other platforms. It is just that people do not know about it.
class Delegated implements Base {
final Base b;
public Delegated(Base b) { this.b = b; }
@Override
public void printMessage() { b.printMessage(x); }
@Override
public void printMessageLine() { b.printMessageLine(x); }
with the Kotlin way https://kotlinlang.org/docs/delegation.html#overriding-a-mem...OT1H, yes, sane people using IJ would just alt-Insert, choose delegate to, and move on with life. But those misguided folks using VS Code, vim, or a magnetized needle and a steady hand would for sure find delegating to a broader interface to be a huge PITA
People use the wrong tool for the job, or use it incorrectly, and then blame the tool. It's like using a hammer to play drums, obliterating the drum set, then ranting against hammers.
> 1. its ok to add incidental and unnecessary complexity
> 2. so long as it's less complex than your most complex component?
That is not my argument.
> You could say that I just did not do it right, but that is the problem. You need to know precisely what the future will want to do it right and that is never possible to know in advance.
Every time inheritance causes a headache, you can call it a misuse of inheritance, but that is only obvious after you have been to the future.