0

A method from an inherited class should return the object type from who has inherited. In C++ this behaviour is easy to accomplish. But I don't know how to do it in javascript. I know it is wrong but I wrote like this.

class A {
 someMethod() {
  return new A();
 }
}
class B extends A {
}
var b = new B();
b.someMethod() // should return an object of type B not A

in C++ this is easy to do

template <typename c>
struct a
{
    a() : _value(NULL) {}
    a(std::string v) : _v(v) {}
    static c* from_string(std::string &v)
    {
        return new c(v);
    }
private:
    std::string _v;
};

struct b : public a<b>
{
    b() : b<a>() {}
    b(std::string &v) : node<b>(a) {}
};

How should this be implemented using javascript?

edit

This is not how inherits a class, is a particular pattern of inheriting and creating objects. There are several examples like Buffer.from, Buffer.alloc from Node.Js. But I would like to reproduce this from a base class.

A guy showed me that my issue could be solved using the following script:

class A {
 method() { return this.constructor(); }
}

class B {}

var b = new B();
var b1 = b.method();

What I really would like to do is something like following.

class A {
 static from() { return new this.constructor() }
};
class B extends A {};

a = A.from();
b = B.from();

a instanceof A // should be true
b instanceof B // should be true.


edit 2

I found something.

I found in typescript the same C++ behaviour can be archived as follows:

class a {

    static from<t extends a>(c: { new(): t }) : t {
        return new c();
    }

};

class b extends a {
}

let b1 = a.from(b);

b1 instanceof b
b1 instanceof a

console.log(b1);

the es6 equivalent is:

class a {
    static from(c) {
        return new c();
    }
}
;
class b extends a {
}
let b1 = a.from(b);
b1 instanceof b;
b1 instanceof a;
console.log(b1);
//# sourceMappingURL=index.js.map
arthur.afarias
  • 140
  • 1
  • 9
  • Possible duplicate of [How to inherit from a class in javascript?](https://stackoverflow.com/questions/2107556/how-to-inherit-from-a-class-in-javascript) – computercarguy Aug 13 '19 at 17:35
  • @computercarguy Have you read through that dupe? How does that answer the question? – Jonas Wilms Aug 13 '19 at 17:36
  • @JonasWilms, not only does it show the correct way to create a JS class, but it also shows how to inherit another class. How is that not answering this question? – computercarguy Aug 13 '19 at 17:38
  • Okay, but they don't use ES6 syntax. Something I missed when asking was if the method is static. – arthur.afarias Aug 13 '19 at 17:51
  • A template class in C++ is not really a class, right? It's a metaclass for constructing classes based on params. Following that logic you can simply create a function in JavaScript that will return a class satisfying your conditions. – freakish Aug 13 '19 at 18:11
  • @freakish, is there any example of how to do it in a proper way? – arthur.afarias Aug 13 '19 at 18:13
  • javascript doesn't have generics/templates – Daniel A. White Aug 13 '19 at 18:26
  • 1
    @arthur.afarias The way you've defined it after edit it obviously cannot be done. This is not an analogy of C++. Note that in C++ you cannot even instantiate `struct a` without template argument. But aside that some smart prototype manipulation can be applied here. I'm working on an answer. – freakish Aug 13 '19 at 18:27
  • I found something, I gonna edit my question. – arthur.afarias Aug 13 '19 at 18:52
  • Then why do you need that `static from(c) {return new c(); }` at all? I don't see a purpose there. This is most likely an XY problem. – Jonas Wilms Aug 13 '19 at 19:08
  • @JonasWilms, to reproduce the same behaviour that I can do in C++. – arthur.afarias Aug 13 '19 at 19:23

1 Answers1

2

As I've commented: a template class in C++ is actually a metaclass. It is used for constructing other classes out of it.

So we can apply this observation to JavaScript. I've played around and here's the closest thing I could get. First define a "template":

function TemplateA(cls) {
    class A {
        static from() {
            return new cls();
        };
        foo() {
            return -1;
        };
    };
    return A;
};

Now define custom "extends":

function Extends(base, derived) {
    // Update statics
    // (these should not be overwritten)
    var common = {name: 1, prototype: 1, length: 1};
    var statics = Object.getOwnPropertyNames(base)
        .filter(el => !common[el]);
    statics.forEach(el => {
        derived[el] = base[el];
    });
    // Update instance methods
    var instanceMethods = Object.getOwnPropertyNames(base.prototype);
    instanceMethods.forEach(el => {
        derived.prototype[el] = base.prototype[el];
    });
};

and finally usage:

class B {
    test() { return 1; }
};

> Extends(TemplateA(B), B);
> var b = B.from();
> b instanceof B;
true
> var x = new B();
> x.foo();
-1
> x.test();
1

It seems to do what you want. This has some drawbacks though. It is not really an inheritance (the prototype is just updated). In particular B is not a subclass of A<B> (actually no such class even exists after Extends). On the other hand JavaScript's inheritance/prototyping is quite unique and very different from C++ and so we can't expect everything to work.

Side notes:

  • Is it safe? Probably. However it does require lots of discipline from a dev. For example it is too easy to overwrite something you didn't want to.
  • Would I use it in prod environment? Unlikely. Whatever you are trying to accomplish most likely can be achieved in some other, standard way. Treat the solution as an academic fun.
  • Finally: who told you that C++ way is the best way? Your swimming skills are not really useful when you are climbing, right? So I strongly suggest you rethink your entire architecture and try to do things differently.
freakish
  • 54,167
  • 9
  • 132
  • 169
  • I am investigating ways on the creation of serialization functions. This architecture in C++ seems to be good. Once you can create serialization trait and serialization function specialization. I am really interested in how to reproduce this pattern in javascript once I would like to create a scalable and reusable code. I don't see any other way in creating this pattern that could be more suitable to the javascript world. – arthur.afarias Aug 13 '19 at 19:10
  • `Object.setPrototypeOf(B.prototype, A.prototype)` ... But you are right with the last part, this is probably not the way to do it. – Jonas Wilms Aug 13 '19 at 19:11
  • @arthur.afarias For that particular problem I would go with a "registry design". I.e. you have a shared `Registry` object and whenever you want to add a serialization method for a class you just do `Registry.register(MyClass, MySerializer);` and then you serialize by calling `Registry.serialize(obj);`. I would even do that in C++ if that was possible (i.e. classes are not first order citizens in C++). – freakish Aug 13 '19 at 19:12
  • @JonasWilms this breaks the prototype chain of `B` if `B` already has a prototype. I don't think there's a win-win here. – freakish Aug 13 '19 at 19:16
  • I think there is no way to reproduce this C++ design pattern in Javascript. But I am going to search another way of how to serialize in a proper javascript design pattern. – arthur.afarias Aug 13 '19 at 19:21