by adamzerner on 10/12/21, 9:40 AM with 59 comments
by spankalee on 10/13/21, 3:35 AM
Printing: Java is verbose because it requires a class. Most languages with classes don't.
The namespacing example in JS is weird because JS has namespaces as pointed out already, but again this case is only a problem in Java where you might use a class just cause everything has to be a class.
Functions: same thing.
Objects: not all languages have a separation between objects and class instances, those that do don't require you to use classes. :shrug:
Object with shared behavior: yes, this is where classes are useful because this is practically the definition of classes.
So the bottom line is use classes for the things they were designed for. Who knew?
by chrismorgan on 10/13/21, 3:11 AM
export default {
email: "alice@example.com",
login: function () { ... }
};
By writing `export`, you’re showing you’re using modules; modules are namespacing, and this file potentially named currentUser.js can contain this instead: export let email = "alice@example.com";
export function login() { ... }
That’s pure namespacing. And yes, export bindings are live, so you can use that like this (though you’re likely to surprise some people—but then, the whole style of the code was dubious in many languages anyway): import { email, login } from "./currentUser.js";
email = "bob@example.com";
login();
Back to the original example: speaking generally, `export default { … }` is a code smell that should normally be replaced with precise exports, which generally make life easier for tooling and consequently for humans. (As a consumer, the precise exports version requires only changing `import currentUser from "./currentUser.js"` to `import * as currentUser from "./currentUser.js"` in such cases.) Seeing so often such abuse of the default export, I have mused whether perhaps it was a misfeature, an injudicious appeasement and compatibility measure for older patterns.by bedobi on 10/13/21, 3:38 AM
To this day, oo advocates can't even agree on what oo even is or means.
Apparently oo as envisioned by Alan Kay was supposed to work like cells in the body that pass messages between each other and take actions independently.
Why? Who knows! It was never really explained why literally one of the most complex systems imaginable, one that we still really have very little idea how it even works, should be the model for what could and should probably be a lot simpler.
Today's modern oo languages are probably very far from what Kay envisioned (whatever that was), but it's remains unclear why classes and objects are "better" than the alternatives.
And before anyone goes and comments aksully code organization blabla like yes but code organization can be great or shit in oo or fp or procedural codebases, it has nothing to do with the "paradigm".
Let alone that the entrenched, canonical, idiomatic coding styles of most modern oo languages encourage state, mutability, nulls, exceptions and god knows how many trivially preventable entire classes of errors. Granted, most have now started to come around and are adopting more fp features and ideas every year, but still.
by boredtofears on 10/13/21, 5:37 AM
You can make those factory functions nearly as concise as the class examples if you wanted:
const createEmployee = (firstName, lastName) => ({ firstName, lastName })
const createContractor = (firstName, lastName) => ({
...createEmployee(firstName, lastName),
//overloaded propeties here
})
const createFullTimeEmployee = (firstName, lastName) => ({
...createEmployee(firstName, lastName),
//overloaded propeties here
})
I've always thought more in terms of consumption - who will be using this code and how will it be used?
My probably unscientific approach being a dutiful Typescript worker bee has been to take the general approach:- Try to just use a function, especially when your output will only be consumed one way
- If the domain of the logic that you are working must encapsulate multiple ways to be consumed and there isn't a clear primary use case, and much of the logic and state should be shared between functions, consider a class
I don't find the end result to be significant for anything other than code cleanliness/readability. Admittedly I've never really had language features themselves be performance bottlenecks doing mostly frontend web work. This may be too specific of an observation of Javascript itself to be a broad opinion though. I'd love to hear someone else's opinion as my experience is not from a compsci background.
by btown on 10/13/21, 4:19 AM
> Substitutability is a principle in object-oriented programming stating that, in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of the program (correctness, task performed, etc.).
If your Ugly Duckling doesn't quack like a duck, or is only raised by a duck but is not one itself (a has-a relationship, ergo composition!)... it probably shouldn't be a subclass of Duck. But if it does those things, and you gain more than you lose from the simplicity of passing around simple objects (okay, the analogy has completely frayed here), it should!
by dexwiz on 10/13/21, 5:22 AM
But if you are working with something like Spring Beans or React Components, classes serve as a decent unit within a framework. They help guide developers to factor their code in blocks of roughly similar size and scope. They help organize a codebase into something explorable for new members. Like chapters in a book, they don’t have to all be the same size, and may vary between books/codebases. That being said, most languages overload classes to be record/objects and namespace modules.
I like functions, and generally agree with the post. But when all you have is functions calling functions it’s not much better than spaghetti in large projects. You can still make a mess with classes, but they give a conventional way to delineate layers.
by throw_m239339 on 10/13/21, 5:08 AM
But I'm glad HN is back about arguing about petty programming stuff nonless rather than partisan politics.
by ajkjk on 10/13/21, 3:03 AM
by cessor on 10/13/21, 8:04 AM
Some of the criticism is really superficial:
function createEmployee(firstName, lastName) {
return {
firstName: firstName,
lastName: lastName,
};
}
OO-Programs have these weird factory functions called constructors that do exactly that. To me, it makes sense that such functions should share their living space with the class that they are creating. Where else would you like to put these functions? "Utils"?As for classes, namespaces and objects: as others have pointed out, this is an implementation detail. In Python, for example, classes are objects. Besides, classes and objects are functions (and the other way around) so it doesn't matter all that much in practice.
What buggs me more is code like this:
class SayHello {
public static void toPerson(String name) {
System.out.println("Hello " + name);
}
}
Sure, comparing it to an empty Python file which just says "print" this looks like an aweful lot of code. However if the paradim is poorly understood, it will seem to be working against you: class Name {
public Name (string name) {
this.name = name;
}
public static void greet() {
System.out.println("Hello " + this.name);
}
}
The programming is different in that you create a declarative network of objects that then ... act. At this level, there is hardly any difference, except that the name has been introduced as a proper concept. Many people will argue that such value objects are expensive or inefficient (which they are) but if that cost hits you hard, you should be asking yourself why you picked a high level language to begin with.Yes, in such a paradigm a place is needed where the entry point lives, but I found it fundamentally useful. Whatever you call the class it: - Can read and encapsulate access to env variables - It can accept commandline arguments (as main(argv[]) indicates) - It's the place to setup and configure your (object)- dependency tree (what IoC/Dependency Injection-Containers are doing) - Or it can be the ultimate exception handler for messages deeper in your program, e.g. where you would start your main message pump / game loop, etc.
The rest is ergonomics.
by DeathArrow on 10/14/21, 7:18 AM
by Swizec on 10/13/21, 2:56 AM
But maybe the past 10 years of functional-ish programming have broken me. There are lots of problem areas where objects fit nicely. Actor based programming is very elegant with classes and objects I think.
by donsupreme on 10/13/21, 2:58 AM
by savant_penguin on 10/13/21, 3:29 AM
And even then I usually try to make a function of a function whenever possible.
I find classes really hard to grasp (multiple inheritance/the syntax often sucks/diamond gotchas). Maybe I just don't understand them, but I've been able to get away without understanding classes for long enough