Hacker News new | ask | show | jobs
by GendingMachine 798 days ago
As a programmer with likely less experience than most of these commenters, the main question that always feels under addressed in these kinds of posts is that of code deduplication.

Most 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.

2 comments

Typescript is best when you don't use `class` or `this` at all, but instead return object literals of static closures. In other words, more like this:

    function makeCounter(initial = 0) {
        let count = initial;
        function get() { return count }
        function inc() { count += 1 }
        function dec() { count -= 1 } 
        return {get, inc, dec}
     }

      // works just like a normal object
      const ctr1 = makeCounter(); 
      ctr1.inc()

      // but this works too.  try doing this with a class instance.
      const {get, inc} = makeCounter() 
      inc()
This is the typical style of most VueJS code (though it would replace count with a ref and probably call the function `useCounter`). TypeScript is smart enough that it can infer interfaces and even classes from such literals should you go that way, full support for substitutability checking and all.
It's always possible to 'deconstruct' objects with methods into just dumb structs with functions acting on them. This is the direction Julia takes for instance.

One advantage of this is that it exposes that 'inheriting' a method is really just applying the same base function to all classes that support a particular interface. You can override a method by specialising the function for a subinterface. This interface can just be a marker that says 'this struct has these fields, and semantically is a 'IMyInterface').

Of course object oriented programming languages tend to encourage private and protected properties and such, which force all of this to take place inside the class. At first I though that that was the best way to avoid a mess, but it prevents you from doing this, possibly leading to more code duplication. And after some more experience with python there's something to be said for python's approach of just using name conventions to point out when to be careful.