3 ms·
I vastly prefer functional programming to OOP. But I find my use of `class` in JS increasing for two reasons orthogonal to the paradigm distinction: 1. Particu
by eyelidlessness 4y ago
I vastly prefer functional programming to OOP. But I find my use of `class` in JS increasing for two reasons orthogonal to the paradigm distinction:
1. Particularly in pure JS projects which either haven’t yet or won’t migrate to TypeScript, classes are an excellent way to define data types. They needn’t be stateful, they can be used just like POJOs in otherwise pure functional code. But their shape is clear (or can/should be), and can be used as both types and runtime references without a lot of ceremony.
2. Classes, when they have a clear shape, are great for performance-sensitive code. POJOs can achieve this, but it’s frequently all too easy for their shape to evolve as a codebase is in maintenance. And that can cause hard to find performance regressions.
- zdragnar 4y agoUsing runtime classes can also be handy if you're willing to use `instanceof` (or the speedier constructor comparison) to disambiguate between types, such as when you want to branch on Left/Right in an Either, or None/Just in a Maybe, or Error/Success in a Result, etc.
- gavinray 4y agoSeconding this
- WorldMaker 4y agoI also tend to prefer functional programming to OOP in JS, but there's a massive legacy of OOP in JS. The `class` syntax really is just syntactic sugar for classic IIFE-wrapped `.prototype.` JS OOP. You can pass modern classes to ancient JS OOP libraries like for instance Dojo and there's sometimes few things quite as satisfying when upgrading legacy code as replacing the classic legacy spaghetti Dojo class definition IIFE with a much simpler `class SomeLegacyWidget extends DojoWidget {}`. Almost no one even needs to know what an IIFE even is or stands for today. It's great. That `class` syntax works in all the modern browsers today, no Typescript transpile or Babel plugin or "polyfill" needed. (Dojo comes to mind because of doing code on current ArcGIS-related projects that are still stuck in the mines of ancient Dojo versions, IIFE "classes", and AMD wrappers. Still great to have Typescript generate the AMD wrappers for you from modern ES2015 module syntax, but `class` and even `await/async` you can get for "free" in modern browsers and are huge clarifying changes to legacy Dojo work.)
- Scarbutt 4y agoImmutability in JS is painful and tedious, how can you enjoy write functional code in JS?
- eyelidlessness 4y agoI don’t find it painful or tedious. - Constructing flat POJO values is trivial (spread + define any changed properties). - Immutable array operations are fairly robust, albeit not as expressive as some may want. Getting comfortable with reduce improves this dramatically. - Map/Set constructors accept instances to create new values. - Class instances used as value types are simple to derive, assuming their constructors accept objects in their shape. If they have a consistent shape, deeply nested clones with consistent descendant classes are equally trivial. - Iterators could play nicer with other native interfaces, but they’re pretty handy even so. Custom iterators are exceedingly handy for shuttling data between types. - More expressive operations over sequence-like structures is as simple as operating on iterators. This will feel more reasonable if you favor Map over POJO for mapped types. - Imperative stateful functions are admittedly a pain, but wrapping them in functions which return meaningful state you’ll need later is pretty straightforward. - Really though, starting from a functional perspective just makes these details a non-issue. If your primary tool is a pure function, any gap in these interfaces can be filled by writing a function and calling it rather than the imperative code. If some or all of that sounds like it’s a performance nightmare… most of the time it isn’t. But if you have a hot loop where copy on write is a meaningful bottleneck: - You can take inspiration from Clojure or other functional languages with persistent data structures. There are a ton of libraries. - You can take inspiration from Clojure or other functional languages with a concept like transients, and isolate your mutable code in a function body. This doesn’t even need a library, it’s just bailing to the imperative code the language ostensibly wants you to write in the first place, and being thoughtful about how it’s encapsulated. What I do find painful and tedious is trying to follow stateful imperative code which hasn’t been subjected to intense discipline. This is true regardless of the language. It’s true whether the code is “object oriented” or not.
- Scarbutt 4y agoThanks Your list sums up why I find it tedious ;), since you mention Clojure, in Clojure one doesn't have to think about those things and go through hoops(except for when doing Java interop). Unfortunately I don't think Clojurescript is worth the hassle(or even immutablejs or immer) and just prefer writing JS and applying your list. Functional programming languages spoil you in this regard.