A way to fire logic at the end of completion of the current class method (regardless of super call order).

# #!/JoePea (2 months ago)

I many times find myself in cases where a base class wants to ensure that logic is always fired after the current method's execution, so that for example no matter in which order sub classes call the super method, the super method can still guarantee that logic fires after the whole stack of the same method in the class hierarchy.

So what I can do now is use Promise.resolve().then(() => { ... }) to

schedule that logic for later, that way all the invocations of a foo method along the class hierarchy have all fired. But this means that other code can also fire before the next microtask.

Is there some way to do it? If not, I wonder if some language feature for doing it would be possible?

# Isiah Meadows (2 months ago)

I've also had several scenarios where I could've used this personally. I feel ES classes are overly restrictive in preventing this, since it basically forces you to force subclasses to do something like this.init() right after the class is allocated, leaking implementation details left and right.


Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# kai zhu (2 months ago)

I feel ES classes are overly restrictive in preventing this, since it basically forces you to force subclasses to do something like this.init() right after the class is allocated, leaking implementation details left and right.

its not a design-flaw. the flaw is you trying to shoehorn “classical” inheritance-based design-patterns on a language better suited to use static-functions to baton-pass json-data (over class-instance).

here’s a real-world example of a dbTableCreateOne static-function to initialize a mongo-like collection/table, and then sync it with indexeddb persistence-store [1]. imagine how much more difficult these [common-case] async-initializations would be using inheritance-based constructors.

local.dbTableCreateOne = function (options, onError) {
/*
 * this function will create a dbTable with the given options
 */
    var self;
    options = local.objectSetOverride(options);
    // register dbTable
    self = local.dbTableDict[options.name] =
        local.dbTableDict[options.name] || new local._DbTable(options);
    ...
    // restore dbTable from persistent-storage
    self.isLoaded = self.isLoaded || options.isLoaded;
    if (!self.isLoaded) {
        local.storageGetItem('dbTable.' + self.name + '.json', function (error, data) {
            // validate no error occurred
            local.assert(!error, error);
            if (!self.isLoaded) {
                local.dbImport(data);
            }
            self.isLoaded = true;
            local.setTimeoutOnError(onError, 0, null, self);
        });
        return self;
    }
    return local.setTimeoutOnError(onError, 0, null, self);
};

p.s. - going off-topic, but above-mentioned code/library (as well as proposals for standard tree/stl libraries) shouldn’t even exist if javascript had a builtin/standard sqlite3 library (like python).

[1] initialize a db-table and sync it with persistence-store kaizhu256/node-db-lite/blob/2018.4.23/lib.db.js#L1861, kaizhu256/node-db-lite/blob/2018.4.23/lib.db.js#L1861

[2] discuss including tree and stl in proposed standard-library tc39/proposal-javascript-standard-library#16, tc39/proposal-javascript-standard-library#16

tc39/proposal-javascript-standard-library#16, tc39/proposal-javascript-standard-library#16

# Jordan Harband (2 months ago)

If the superclass constructor has a way to run any code after subclass constructors, then implementation details of the subclasses are then leaked.

# Isiah Meadows (2 months ago)

I get that, but it's usually part of the API subclassing contract that the superclass explicitly depends on certain parts of the subclass. Abstract classes immediately come to mind, and I'd say it's no more leaking than any inherited method. It's not giving them any more access to information than they would've gotten from an explicit if (new.target === Subclass) this.init() call at the end (which is basically what I want mod the exposed method).


Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# Isiah Meadows (2 months ago)

I presume you've never written non-trivial server-side logic in Node. I find myself using classes far more often in Node than in the browser simply because it's more than just passing strings and object bags around. You've got caching, process management, and even sometimes task queues. The traditional MVC architecture doesn't need classes to implement in Node (and the corresponding idioms don't use them, either), but it's all the machinery around it that result in all the server-side classes.

Also, I'd like to note a few things:

  • Some functional languages, notably OCaml, support classes with classical inheritance. Inheritance does actually help from time to time.
  • JS is not opinionated on the matter - it supports both styles. In fact, it lacks some of the utilities for pure POJO passing and manipulation, while classes are mostly complete. In reality, it's slightly biased in favor of classes, something several people have been complaining about (me included).
  • I'm very well used to passing POJOs around to static functions - it's called functional programming.
# Michael Haufe (2 months ago)

You can use a Proxy in the base class:

<script>

let handlerExample = { get(target, prop) { let feature = target[prop] return feature instanceof Function ? function () { console.log('Before call'); let result = feature.apply(this, arguments) console.log('After call'); return result } : feature } }

class Base { constructor() { return new Proxy(this, handlerExample) } m1() { return "m1" } }

class Sub extends Base { m1() { return override ${super.m1()} } m2() { return m2 } }

let base = new Base() console.log(base.m1())

let sub = new Sub() console.log(sub.m1()) console.log(sub.m2()) </script>

/Michael

On Fri, Feb 8, 2019 at 1:22 AM #!/JoePea <joe at trusktr.io> wrote:

I many times find myself in cases where a base class wants to ensure that logic is always fired after the current method's execution, so that for example no matter in which order sub classes call the super method, the super method can still guarantee that logic fires after the whole stack of the same method in the class hierarchy.