I'm looking for a way to implement an abstract static method in TypeScript.
Here an example:
abstract class A {
abstract static b (): any // error
}
class B extends A {
static b () {}
}
This is allowed with public, private and protected methods but not with a static method. TypeScript returns the following error:
'static' modifier cannot be used with 'abstract' modifier.ts(1243)
Is there any workaround?
I think the reasoning is generally as follows:
Abstract methods are placeholders that a concrete subclass is supposed to implement.
The abstract base class will have a concrete method which uses this abstract placeholder, and thus requires it to be implemented; without this, abstract methods make little sense at all. E.g.:
abstract class Foo {
bar() {
return this.baz() + 1;
}
abstract baz(): int;
}
This can only be called on a concrete instance, e.g.:
function (foo: Foo) {
let val = foo.bar();
...
}
The result will be different here depending on what concrete subclass of Foo you get, but it's all guaranteed to work.
Now, what would this look like with static methods?
abstract class Foo {
static bar() {
return this.baz() + 1;
}
abstract static baz(): int;
}
function (F: typeof Foo) {
let val = F.bar();
...
}
This looks somewhat logical and like it should work, shouldn't it? But:
If you write this, there's basically no difference to passing instances of classes, except for the awkward typeof typing. So, why?
If you never instantiate the class, what's the point of a class?
If your static method does instantiate an object, if it acts as an alternative constructor—which is entirely legitimate—then calling F.bar() to get a new instance, you'd expect to get an instance of F, but you might be getting an instance of some subclass of it. And that's arguably not desired.
To rephrase the chain of argument here:
If you're going to use static methods at all, they should act as alternative constructors and return an instance, otherwise they have little business being part of the class.
Alternative constructors should return an instance of the class that you called them on. Calling F.bar() and not getting an instance of exactly F is… weird?
If you're going to call static alternative constructors on classes, you're going to want to call them on specific classes and not variables as shown above, because otherwise you really won't know what you're getting (see point above).
Therefore, there's no real use case for an abstract static method, either as direct alternative constructor nor as helper function for one, since that would lead to a violation of one of the above points one way or another.
As far as I see, this is pretty much the classical thinking that lead to abstract static methods not being a thing. Certain technical limitations in Java may have contributed to that and/or lead to said technical limitations in the first place.
In Javascript one can argue that this makes less sense, since even classes are objects and it would be entirely feasible to use them as described above, and in certain situations it may even make sense. But here we are.
Related
I am writing an object pool class that holds onto old unused objects, and when a new one is needed can use one of its reserves (Without the expensive creation of objects). However, I want to be able to save any data to this pool (not limited to something such as extends Poolable). The problem is that most object pools require something like this:
class MyData {
constructor(str) {
this.reset(str)
}
reset(str) {
this.str = str;
}
}
So that when a new instance is needed, the pool can call oldInstance.reset(prams). As stated before, I do not want this (Working with lots of third party tools that I am not feeling like writing wrappers for), so my data looks like this:
class MyData {
constructor(str) {
this.str = str;
}
}
When the pool needs to reset an instance, I need to be able to call the constructor as a function and set the this value to the instance that is being wiped.
This is super easy with old classes that used function/prototype syntax when they were made:
const MyClass = function(str) {
this.str = str;
}
// Reset an instance
const instance = new MyClass("foo");
MyClass.apply(instance, ["bar"])
// done
However when I do that for classes, it complains that you can not use a class without the new keyword. How do I go about doing this?
Fiddle: https://jsfiddle.net/wuqek405/
Edit:
As I said, most object pools need a reset function. I am trying to use the constructor as this function, because it is supposed to “set up” the instance. Another solution would be to generate this reset function based on the class. However, I want it to be as fast as possible, so terribly hacky solutions such as stringifying the class and evaling the constructor wouldn’t be optimal.
This is not possible. A class is not callable1, only constructable - which means creating a new object. This was new in ES6, which overhauled the inheritance model of classes and introduced super. Also, ES2022 will introduce class fields, which also get created during construction without being mentioned in the constructor code.
Your only option is to use only ES5 function-based classes, a transpiler, or writing explicit reset methods.
1: technically, it is callable (typeof C == 'function'), but [[Call]] will always throw an exception
I am learning about compositions in Javascript. So I want to ask if this is correct way of doing things.
I made some exercises that look like this:
class Animal {
// constructor() {
// }
eat = () => {
console.log("this creature is eating");
}
}
const AnimalsWithWings = superclass => class extends superclass {
constructor(Feathers, ...args) {
super(...args);
Object.assign(this, { Feathers });
}
}
const CanDive = superclass => class extends superclass {
// constructor( ...args) {
// super(...args);
// }
dive = () => {
console.log("Can Dive");
}
}
class Duck extends AnimalsWithWings(CanDive(Animal)) {
constructor(eats, ...args) {
super(...args);
Object.assign(this, { eats });
}
}
const duffy = new Duck("watermelon", true);
console.log(duffy);
duffy.dive();
duffy.eat()
I am still in learning process so I just need some pointers.
Did it do more or less what you expected? Then, sure, it's a correct way to do it, whatever "correct" means here.
It looks to me like it does what it was meant to do when I pop it into the console. I can't really say much more on your code specifically because I'm not sure what concrete domain it's trying to model, aside from maybe breaking down Ducks into atomic pieces.
If you're going to do it this way, though, I'd personally prefer to use a params object instead of just changing the constructor signature like that with AnimalsWithWings. That way, the order of extra parametrizations doesn't depend on the order in which the mixins were applied, which I would consider a Surprise. Surprises are bad.
const AnimalsWithWings = superclass => class extends superclass {
// Everyone receives the same `params` object.
// They only take what they know about, and ignore the rest.
constructor(params) {
super(params);
Object.assign(this, { Feathers: params.Feathers });
}
}
Even more personal opiniony, I'd name them WithDiving and WithWings instead, just to keep a somewhat consistent naming scheme, and to better imply that these are modifiers, not "real" base classes.
Your code does saddle every Duck with a prototype chain 4 prototypes long, but eh, whatever. If it somehow becomes a performance problem then you can create a utility function to optimize the mixin process or something. Flatten the prototypes, maybe.
Your code does also let you call super.method() in methods, though it's debatable whether you should ever use that in a mixin at all. I'd say you shouldn't, unless you want your mixins to implicitly depend on each other, which is a Surprise.
There are plenty of other ways of doing mixins, too.
You could create a utility function to flatten all the prototypes into a single new one and return a base class from that which you extend. (Just be sure to iterate property descriptors rather than just using Object.assign() when doing that flattening, if you want to properly handle things like get/set accessors, etc.)
You could eschew Classes and just directly create prototype objects and use Object.create() to create instances. (same thing about iterating property descriptors.)
You could create a Duck prototype using a bunch of iterative calls to Object.create() instead of iteratively extending base classes.
You could control the additional behaviors with helper Controller Classes instead of composing behavior directly into the base.
You could deal just in plain objects with data, and pass the objects to functions that expect the object to have certain properties on it in order to do things. (Amusingly, called "duck typing") I'll grant that's not really mixins, just calling functions, but if it accomplishes the same thing in effect...
Probably a bunch others I can't really think about at the moment. It's all sticking sets of behaviors onto some base thing.
JavaScript's class syntax, added in ES6, apparently makes it legal to extend null:
class foo extends null {}
Some Googling reveals that it was suggested on ES Discuss that such declarations be made an error; however, other commenters argued for them to be left legal on the basis that
someone might want to create a class that has a {__proto__: null} prototype
and that side of the argument ultimately prevailed.
I can't make much sense of this hypothetical use case. For one thing, while the declaration of such a class is legal, it seems that instantiating a class declared in this way isn't. Trying to instantiate the class foo from above in Node.js or Chrome gives me the wonderfully daft error
TypeError: function is not a function
while doing the same in Firefox gives me
TypeError: function () {
} is not a constructor
It doesn't help to define a constructor on the class, as shown in MDN's current example of the feature; if I try to instantiate this class:
class bar extends null {
constructor(){}
}
then Chrome/Node tell me:
ReferenceError: this is not defined
and Firefox tells me:
ReferenceError: |this| used uninitialized in bar class constructor
What is all this madness? Why are these null-extending classes not instantiable? And given that they're not instantiable, why was the possibility of creating them deliberately left in the spec, and why did some MDN author think that it was noteworthy enough to document? What possible use case is there for this feature?
EDIT (2021): TC39, which specifies JavaScript still hasn't resolved exactly how this is supposed to work. That needs to happen before browsers can consistently implement it. You can follow the latest efforts here.
Original answer:
Instantiating such classes is meant to work; Chrome and Firefox just have bugs. Here's Chrome's, here's Firefox's. It works fine in Safari (at least on master).
There used to be a bug in the spec which made them impossible to instantiate, but it's been fixed for a while. (There's still a related one, but that's not what you're seeing.)
The use case is roughly the same as that of Object.create(null). Sometimes you want something which doesn't inherit from Object.prototype.
To answer the second part:
I can't make much sense of this hypothetical use case.
That way, your object won't have Object.prototype in its prototype chain.
class Hash extends null {}
var o = {};
var hash = new Hash;
o["foo"] = 5;
hash["foo"] = 5;
// both are used as hash maps (or use `Map`).
hash["toString"]; // undefined
o["toString"]; // function
As we know, undefined in fact is not a function. In this case we can create objects without fearing a call on a field that shouldn't be there.
This is a common pattern through Object.create(null) and is common in a lot of code bases including big ones like NodeJS.
It is in fact possible to construct a class that extends null, as such
class bar extends null{
constructor(){
super() //required
}
}
//super is not a function
//change the super class (for static methods only)
Object.setPrototypeOf(bar, class{})
let instance = new bar()
//instances still have null prototype
console.log(instance.toString) //undefined
I was writing some OOP code in Javascript and the design of the inheritance raised a question. Like Java should super constructor call be the first line in subclass constructor in Javascript?
var Effect = function (container, height, width) {};
var XEffect = function (container, height, width, resource) {
Effect.call(container, height, width ); // really necessary to be first line?
};
To quote Douglas Crockford: "JavaScript has a class-free object system in which objects inherit properties directly from other objects. This is really powerful, but it is unfamiliar to classically trained programmers. If you attempt to apply classical design patterns directly to JavaScript, you will be frustrated. But if you learn to work with JavaScript's prototypal nature, your efforts will be rewarded."
Check out Object.prototype for how inheritance is handled in JavaScript.
In your code snippet, Effect.call(container, height, width); would simply evaluate as undefined unless you specifically define it before hand. To call the functionality of your Effect function, you would simply invoke it as Effect().
It depends on exactly what the Effect constructor does.
The object and its prototype chain are already set up by the time you reach the first line of code in the constructor. That is to say, before XEffect's constructor is set up, this already exists, and its __proto__ is already set to XEffect.prototype. So your object is already an XEffect, which inherits from Effect.
However, by this point, none of the code in Effect or XEffect has been run yet. The XEffect code will be run, since it's part of the constructor function, but Effect won't be run unless you tell JavaScript to do so. If you wish to call Effect explicitly, you can. As you described, Effect.call(this, ...) or Effect.apply(this, []) are probably the ways you'd want to do that.
The catch is that Effect runs when you tell it to run: no later, no sooner. If Effect writes to some properties of the object, and then code later in XEffect writes to those same properties, XEffect wins: those are the values that the object will have when its over. If you reverse this order -write to properties inside XEffect, then call Effect, which writes to those same properties- then Effect wins.
If you're used to writing in a "class-based" style, then calling Effect first is probably closest to what you want. It writes to the object's properties, and then XEffect (potentially) overwrites them. But you don't have to do it that way, if you have some reason that you want Effect to win.
Personally, I don't like the object-oriented systems implemented in languages like Java and C++. My favourite object-oriented system is that implemented by the Fortress programming language. For example, consider the following Fortress code taken from the famous blog post Why Object-Oriented Languages Need Tail Calls written by Guy Steele (a.k.a. The Great Quux):
trait IntSet
getter isEmpty(): Boolean = false
adjoin(x: ZZ): IntSet = AdjoinObject(self, x)
union(other: IntSet): IntSet = UnionObject(self, other)
contains(y: ZZ): Boolean
end
object AdjoinObject(s: IntSet, x: ZZ) extends IntSet
contains(y: ZZ) = (y = x) OR: s.contains(y)
end
object UnionObject(s1: IntSet, s2: IntSet) extends IntSet
isEmpty: Boolean = s1.isEmpty AND s2.isEmpty
contains(y: ZZ) = s1.contains(y) OR: s2.contains(y)
end
object EmptyObject extends IntSet
isEmpty: Boolean = true
contains(y: ZZ) = false
end
Object definitions in Fortress introduce object constructors. These constructors may either be nullary (e.g. EmptyObject) or parameterized (e.g. AdjoinObject and UnionObject).
Traits are similar to abstract base classes. Hence, you can't create an instance of a trait directly. Instead you need to create a concrete object that implements the interface of the trait.
Note that in this scenario you never need to call a superclass constructor because there is no superclass constructor. All the superclasses (traits) are abstract. They have no state and hence they do not need to be initialized. The state of the object is encapsulated within the object constructor. This is important because it promotes data abstraction, an important property of object-oriented programs.
So how would this Fortress code look in JavaScript?
There are many ways to write object-oriented code in JavaScript. However, the following Fortress-style object-oriented JavaScript code is my favorite:
class IntSet {
get isEmpty() { return false; }
adjoin(x) { return AdjoinObject(this, x); }
union(other) { return UnionObject(this, other); }
contains(y) { throw new Error("Abstract method invocation"); }
}
const AdjoinObject = (s, x) => new class extends IntSet {
contains(y) { return y === x || s.contains(y); }
}
const UnionObject = (s1, s2) => new class extends IntSet {
get isEmpty() { return s1.isEmpty && s2.isEmpty; }
contains(y) { return s1.contains(y) || s2.contains(y); }
}
const EmptyObject = new class extends IntSet {
get isEmpty() { return true; }
contains(y) { return false; }
}
const Empty = EmptyObject;
const example = Empty.adjoin(1).adjoin(2).union(Empty.adjoin(3));
console.log(example.contains(1)); // true
console.log(example.contains(2)); // true
console.log(example.contains(3)); // true
console.log(example.contains(4)); // false
Uncomplicated solid object-oriented programming in JavaScript. In addition, you do not need to worry about superclass constructors.
For a long time I have been throwing around the idea of making my JavaScript more object oriented. I have looked at a few different implementations of this as well but I just cannot decide if it is necessary or not.
What I am trying to answer are the following questions
Is John Resig's simple inheritance structure safe to use for production?
Is there any way to be able to tell how well it has been tested?
Besides Joose what other choices do I have for this purpose? I need one that is easy to use, fast, and robust. It also needs to be compatible with jQuery.
Huh. It looks much more complicated than it needs to be, to me.
Actually looking more closely I really take exception to what it is doing with providing this._super() whilst in a method, to call the superclass method.
The code introduces a reliance on typeof==='function' (unreliable for some objects), Function#toString (argh, function decomposition is also unreliable), and deciding whether to wrap based on whether you've used the sequence of bytes _super in the function body (even if you've only used it in a string. and if you try eg. this['_'+'super'] it'll fail).
And if you're storing properties on your function objects (eg MyClass.myFunction.SOME_PRIVATE_CONSTANT, which you might do to keep namespaces clean) the wrapping will stop you from getting at those properties. And if an exception is thrown in a method and caught in another method of the same object, _super will end up pointing at the wrong thing.
All this is just to make calling your superclass's method-of-the-same name easier. But I don't think that's especially hard to do in JS anyway. It's too clever for its own good, and in the process making the whole less reliable. (Oh, and arguments.callee isn't valid in Strict Mode, though that's not really his fault since that occurred after he posted it.)
Here's what I'm using for classes at the moment. I don't claim that this is the “best” JS class system, because there are loads of different ways of doing it and a bunch of different features you might want to add or not add. But it's very lightweight and aims at being ‘JavaScriptic’, if that's a word. (It isn't.)
Function.prototype.makeSubclass= function() {
function Class() {
if (!(this instanceof Class))
throw 'Constructor function requires new operator';
if ('_init' in this)
this._init.apply(this, arguments);
}
if (this!==Object) {
Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
}
return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};
It provides:
protection against accidental missing new. The alternative is to silently redirect X() to new X() so missing new works. It's a toss-up which is best; I went for explicit error so that one doesn't get used to writing without new and causing problems on other objects not defined like that. Either way is better than the unacceptable JS default of letting this. properties fall onto window and mysteriously going wrong later.
an inheritable _init method, so you don't have to write a constructor-function that does nothing but call the superclass constructor function.
and that's really all.
Here's how you might use it to implement Resig's example:
var Person= Object.makeSubclass();
Person.prototype._init= function(isDancing) {
this.dancing= isDancing;
};
Person.prototype.dance= function() {
return this.dancing;
};
var Ninja = Person.makeSubclass();
Ninja.prototype._init= function() {
Person.prototype._init.call(this, false);
};
Ninja.prototype.swingSword= function() {
return true;
};
var p= new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person &&
n instanceof Ninja && n instanceof Person
Superclass-calling is done by specifically naming the method you want and calling it, a bit like in Python. You could add a _super member to the constructor function if you wanted to avoid naming Person again (so you'd say Ninja._super.prototype._init.call, or perhaps Ninja._base._init.call).
JavaScript is prototype based and not class based. My recommendation is not to fight it and declare subtypes the JS way:
MyDerivedObj.prototype = new MySuperObj();
MyDerivedObj.prototype.constructor = MyDerivedObj;
See how far you can get without using inheritance at all. Treat it as a performance hack (to be applied reluctantly where genuinely necessary) rather than a design principle.
In an a highly dynamic language like JS, it is rarely necessary to know whether an object is a Person. You just need to know if it has a firstName property or an eatFood method. You don't often need to know if an object is an array; if it has a length property and some other properties named after integers, that's usually good enough (e.g. the Arguments object). "If it walks like a duck and quacks like a duck, it's a duck."
// give back a duck
return {
walk: function() { ... },
quack: function() { ... }
};
Yes, if you're making very large numbers of small objects, each with dozens of methods, then by all means assign those methods to the prototype to avoid the overhead of creating dozens of slots in every instance. But treat that as a way of reducing memory overhead - a mere optimisation. And do your users a favour by hiding your use of new behind some kind of factory function, so they don't even need to know how the object is created. They just need to know it has method foo or property bar.
(And note that you won't really be modelling classical inheritance in that scenario. It's merely the equivalent of defining a single class to get the efficiency of a shared vtable.)