Earlier quoted context omitted.
On the contrary, Tailwind's ergonomics are what attract me to it. With the autocomplete features via the VSCode intellisense plugin, I'm able to create UIs at a pretty extraordinary pace. As a trivial example, let's imagine we need to apply a border radius to an element. Without Tailwind, it looks like this: 1. I find the element I need to style 2. I look at which class it's using 3. I navigate to my CSS file 4. I sc…
I actually just downloaded the VS Code extension earlier today as a result of this discussion, perhaps that will change my opinion. Because for me the two flows would be: 1. I find the element I need to style 2. I add/edit the inline style={{}} attribute I have for it by typing `sty {borrad ` 3. I add a value VS: 1. I find the element I need to style 2. I add/edit the className attribute 3. I pull up the tailwind doc…
If Inheritance is so bad, why does everyone use it?
251–260 of 389 posts
Re: If Inheritance is so bad, why does everyone use it?
#252I don't think inheritance is bad at all. It is very often the easiest way by far to model a problem. Sure, it's not perfect, but I think it is wildly overhated by a vocal minority.
Have you ever seen wildly over-architected OO code where everything seems to be an abstract class and it seems impossible to find out where stuff actually happens? Inheritance is like a lot specialised tools - it can be useful in some situations but I think those are rarer than supporters might thing. Completely refusing to use inheritance and always using inheritance both seem like extreme views that should be avoid…
Re: If Inheritance is so bad, why does everyone use it?
#253Earlier quoted context omitted.
Protocols as a term have other prior art. Which shouldn’t be surprising because a protocol is also descriptive of interface boundaries between software products (such as, but not limited to, network protocols).
The term is unintuitive to me in that usage, because to me a protocol implies an exchange or a sequence of steps between two or more parties, such as in network or cryptographic protocol or a diplomatic protocol. Interfaces, however, only specify one endpoint of an interchange, in an inherently asymmetric way, and they primarily specify operation signatures, where there are often few constraints on the possible seque…
Re: If Inheritance is so bad, why does everyone use it?
#254The key is "prefer composition to inheritance" and dates back to Gang of Four. The word "prefer" is critical to understand. It just means "usually choose A over B" not "B is never the right answer." Unfortunately, since we - as an industry - like hard and fast rules, we move towards that second explanation and act like inheritance never makes sense. Like any tool, there's a time and place where it is the best tool, o…
The GoF book itself is full of examples that use inheritance, but somehow the bumper-sticker-sized advice has taken on a life of its own.
Re: If Inheritance is so bad, why does everyone use it?
#255Earlier quoted context omitted.
Traits and contracts or interfaces, but even still inheritance has it's merits. Being fast and easy is a benefit, and I find defensive programming in extensible systems can benefit from a foundation of expecting inheritance.
What do you mean by this sort of defensiveness? Can you give an example?
It's good for frameworks and extensible systems where your code needs to guarantee certain things will happen when running third party code.
Re: If Inheritance is so bad, why does everyone use it?
#256Re: If Inheritance is so bad, why does everyone use it?
#257I feel people don't understand what inheritance and (object orientation in general) is useful for, misuse it, and then it gets a bad reputation. It's not about making nice hierarchies of Cars, Fruits, and Ovals. For me the main point is (runtime) polymorphism. E.g. you have a function that takes a general type, and you can pass multiple specific types and it will do the right thing. And if you want to avoid huge if-e…
I feel people don't understand what inheritance and (object orientation in general) is useful for, misuse it, and then it gets a bad reputation. It's not about making nice hierarchies of Cars, Fruits, and Ovals. Agree 100%. It starts from the earliest programming course where we just teach it all wrong; way to abstract (no pun intended). One point to add to yours: well executed OOP allows for "structural" flow of con…
Re: If Inheritance is so bad, why does everyone use it?
#258Most specifically, often when encountering a situation in which I have two slightly different classes/types that need to be polymorphic with each other, all the standard non-inheritance based approaches seem to require a lot of outright identical code implementing a shared interface, a bunch of boilerplate composition proxy methods that just point to methods in a composed class, or weird and obscure language features that never really feel like the "intended" approach.
Typescript especially seems to demand really awkward and obtuse implementations of basic mixins or abstract classes and the like, I always feel like I'm missing the more "intended" approach whenever I try to share code between similar classes.
Often discussions around this are awash with talk of traits and delegates and other cool features that seem to only exist in a handful of languages, and never the ones I happen to be required to use at that given moment.
Re: If Inheritance is so bad, why does everyone use it?
#259I only use inheritance for what the author calls ontological inheritance. For example, I find it useful to represent expressions and statements. I prefer composition if I'm trying to reuse data structures.
But ontological inheritance is the worst kind . Because your ontology is wrong. Similar things are kinda different. Different things are kinda similar. Your ontology is based on the linguistic remnants of taxonomic garbage from hundreds of years ago. There's no shelf.
Re: If Inheritance is so bad, why does everyone use it?
#260I feel people don't understand what inheritance and (object orientation in general) is useful for, misuse it, and then it gets a bad reputation. It's not about making nice hierarchies of Cars, Fruits, and Ovals. For me the main point is (runtime) polymorphism. E.g. you have a function that takes a general type, and you can pass multiple specific types and it will do the right thing. And if you want to avoid huge if-e…
I feel people don't understand what inheritance and (object orientation in general) is useful for, misuse it, and then it gets a bad reputation. It's not about making nice hierarchies of Cars, Fruits, and Ovals. Agree 100%. It starts from the earliest programming course where we just teach it all wrong; way to abstract (no pun intended). One point to add to yours: well executed OOP allows for "structural" flow of con…
I think the first part of the first article immediately introduces an anti-pattern - forcing the user to make an instance of a class just to be able to call a pure function. It's just unnecessary noise, either make them static methods, group them in an object literal, or import the module as a namespace.
Adding the "pattern" as a mutable public field is a bit sketchy, and would make it show up in intellisense, but hopefully nobody will access/modify it. Making the pattern as a `const` at module scope solves that problem but you handwave away that approach saying it "pollute the symbol space for intellisense", which isn't true (non-exported items aren't available outside the module).
The next section on validation is a good example of another anti-pattern. The example of:
public get isUserValid(): boolean
is not a good way of doing it, because it relies on hopes and prayers that the user of the class remembers to call this. A better signature would be: function isUser(input: unknown): input is User
Notice the key difference - you can't get an instance of User without it being valid. There shouldn't be a notion of "yeah I have a User, but I don't know if it's a valid User". Your way allows people to operate with User, blissfully unaware of whether it is valid or not, hoping that they might notice the right method to call. Instead: Parse, Don't Validate [1]Note that to do this correctly, you have to either:
1. Separate data and functions 2. If you must use a class, then hide the constructor and provide a static constructor with a return type that indicates the function can fail
[1] https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...
_________
Part 2 was an interesting exercise in how the popular OOP patterns from the GoF book vastly overcomplicated code, negatively impact readability, and make following the code feel like Mario (the princess is in another castle)
No need for inheritance, abstract base classes, of any of that complexity, all of that could be done with:
type ShippingCalculator = () => number
const shippingCalculators = {
USPS: calculateUSPS,
UPS: calculateUPS,
FedEx: calculateFedEx,
DHL: calculateDHL,
} as const satisfies Record
Intellisense works fine of course, and code navigation (via F12) is straightforward and easy to navigate.