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.
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.
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.
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.
I've never really had the problem that I've read an OOP text and felt "this was too short".
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.
Bottles of OOP - https://news.ycombinator.com/item?id=12129821 - July 2016 (71 comments)
Class Foo.__init__(self, db, blob_storage, secrets_manager, …)
Instead of class Foo(DB, BlobStorer, SecretsMgr)
Etc
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? :)
So you have to use composition.
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
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+...
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.
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.
Anyways yeah give me composition and flat classes all day long.
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.
That would save quite a hassle, especially on mobile.
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.
How???
You can only edit the submission title. If you want to edit the link, email the mods.
Edit to add: Bottle's own FAQ says so: https://bottlepy.org/docs/dev/faq.html#what-about-flask
Demonstrating for the umpteenth time that automated clairvoyance is an idiotic idea.
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.
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.
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.
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.
B. Functions and structs.
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.
The biggest problem with accidental complexity _is_ how hard it is to refactor code. Refactoring code is a huge part of software development.
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?
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?"
>> 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'.
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.
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.
1. its ok to add incidental and unnecessary complexity
2. so long as it's less complex than your most complex component?
Because that's a formula we can all agree leads no where good nor productive.
> 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.
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.
That's all I got. Best of luck!