Proposal: Class Templates
From what I understand (that is, not much), class templates are useful in strongly typed languages, so that one can have a family of classes that share the same implementation but that derive from different types; e.g. Stack<int> for stacks of ints and Stack<string> for stacks of strings. In JS, you can have one Stack class that accepts both ints and strings, so that this use case doesn’t apply (or, at least, it is not a necessity).
But I'm sure there are other use cases. What are they, and are they compelling enough?
Reflection would be nice, but that's about the only use case I can think of. Being able to tell a typed number array from a typed object array would be useful for some array processing optimizations and maybe stream processing optimization, but that's about it AFAIK.
Also, it's worth mentioning Julia exists as language precedent here: it's got generic runtime types in the form of both classes and type aliases, despite being a dynamically typed, JIT-compiled language.
Isn't it already solvable by:
const SizedArray = (size) => class SizedArray extends Array {
constructor(...args) { if(args.length > size) throw new SyntaxError('Argument size is too big.') super(...args) } push(i) { if(this.length + 1 > size) throw new SyntaxError('Cannot push
items anymore, array too big.') super.push(i) }
}
const arr = new (SizedArray(5))?
“Strongly typed” Strongly typed is not Statically typed. Python is strongly typed for example. Strongly typed language means that ”something” + 1
will throw error, Weakly typed means that ”something” + 1
will turn 1
into string and add it to something
, which will result in something1
.
Statically typed language means that once you do Boolean Abc = true
, or let Abc: Boolean = true
, you can’t change it to number, but you can change it to false
, or true
.
Did you mean Statically typed language?
Also, I think that there can be usefulness in class templates, without language being Statically typed.
Yes, you can do that. But then doesn’t that look ugly?
new (Abc(1, 2, 3))(4, 5, 6)
, vs new Abc<4, 5, 6>(1, 2, 3)
.
On Wed, Jan 16, 2019 at 1:01 PM ViliusCreator <viliuskubilius416 at gmail.com> wrote:
Yes, you can do that. But then doesn’t that look ugly?
new (Abc(1, 2, 3)(4, 5, 6)
, vsnew Abc<4, 5, 6>(1, 2, 3)
.
You meant new (Abc(4, 5, 6))(1, 2, 3)
vs. new Abc<4, 5, 6>(1, 2, 3)
, right? There's not a lot in it... :-)
The problem you face is that new Abc<4>(1, 2, 3)
(where there's only one thing within the <>, presumably a common case) is already valid syntax:
new Abc<4>(1, 2, 3)
becomeso<4>(1, 2, 3)
becomesb1>(1, 2, 3)
becomesb1>3
becomesb2
...where o
is the object created by new Abc
(parens are optional in new
if there are no arguments), b1
is the boolean resulting from o<4
, and b2
is the boolean resulting from b1>3
.
Even though nearly-nonsensical, assigning valid syntax new meaning is a very high barrier to jump. (Interestingly, if weren't the case that <
after new Identifier
is already valid syntax, the spec changes to enable making new Abc<x>
call Abc with x and then use new on the result [no need to tie it specifically to some "class templates" concept] would be fairly small [tagged templates already work that way]. But...) You'd need new Abc<|4|>
or similar, and...that seems like it's unlikely to happen.
I want to reach for tag functions here, but it would be either ugly:
new Abc`${4}${5}${6}`(1, 2, 3)
...or an awful and limited hack...
new Abc`4, 5, 6`(1, 2, 3)
(parsing the "arguments" in the template from the strings array passed to the tag function).
new (Abc(4, 5, 6))(1, 2, 3)
starts looking pretty good. :-)
-- T.J. Crowder
Le 16 janv. 2019 à 13:57, ViliusCreator <viliuskubilius416 at gmail.com> a écrit :
“Strongly typed” Strongly typed is not Statically typed. Python is strongly typed for example. Strongly typed language means that
”something” + 1
will throw error, Weakly typed means that”something” + 1
will turn1
into string and add it tosomething
, which will result insomething1
.Statically typed language means that once you do
Boolean Abc = true
, orlet Abc: Boolean = true
, you can’t change it to number, but you can change it tofalse
, ortrue
.Did you mean Statically typed language?
Also, I think that there can be usefulness in class templates, without language being Statically typed.
I meant ”statically typed”, yes. But I think you understood what I meant. My question was about compelling use cases in JS. We know that you think it is useful, but you should convince others that it is useful, that is to say, worth the added complexity in the language.
In the proposal:
class SizedArray<size> extends Array { constructor(...args) { if(args.length > size) throw new SyntaxError('Argument size is too big.') super(...args) } push(i) { if(this.length + 1 > size) throw new SyntaxError('Cannot push items anymore, array too big.') super.push(i) } }
Usage: Usage is simple, and obvious.
// ... let somethingElse: A<Number> = new A<Number>;
I don't think the syntax is obvious. What will happen in the if inside
the constructor? What value size
would receive? Infinity? undefined?
The Number
function?
That's no way templates will ever work like that in Javascript, it
doesn't makes any sense, C++ templates were implemented to support
generic static allocation and safe typings, neither of this features
applies to Javascript (and probably never will). Your example could
easily be written with constructor arguments (like any sane OOP
language), that's not a problem to be solved here
class SizedArray extends Array {
constructor(size, ...args) {
if (args.length > size) throw Error();
super(args);
}
}
You could use
new Abc`abc`(‘abc’)
But you could only use strings. What about constructors? You would need to use
const thatConstructor = (new Function(‘return ’ + t))()
But it would only give what is defined in that constructor.
This email has been checked for viruses by Avast antivirus software. www.avast.com/antivirus
Also, using new (Abc(4, 5, 6))(1, 2, 3)
causes error Uncaught TypeError: Abc(...) is not a constructor
.
This email has been checked for viruses by Avast antivirus software. www.avast.com/antivirus
michaelficarra/proposal-first-class-protocols may be a more palatable approach here.
On Wed, Jan 16, 2019 at 5:29 PM ViliusCreator <viliuskubilius416 at gmail.com> wrote:
You could use
new Abc`abc`(‘abc’)
I think you must have missed my earlier reply, which
covered that, and also the fact that the major problem with using <>
for this is that it's already valid syntax (in a common use case) meaning something else (something almost nonsensical, but valid nonetheless).
On Wed, Jan 16, 2019 at 5:41 PM ViliusCreator <viliuskubilius416 at gmail.com> wrote:
Also, using
new (Abc(4, 5, 6))(1, 2, 3)
causes errorUncaught TypeError: Abc(...) is not a constructor
.
Not if Abc
is written correctly, for instance like Michał Wadas did with SizedArray
earlier in this thread. Abc
example:
const Abc = (a, b, c) => {
// ...optionally do something with a, b, and c...
// Return a class
return class Abc$ {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
// ...optionally do something with a, b, and c...
show() {
console.log(`a = ${a}, b = ${b}, c = ${c}`);
console.log(`x = ${this.x}, y = ${this.y}, z = ${this.z}`);
}
};
};
const obj = new (Abc(4, 5, 6))(1, 2, 3);
obj.show();
-- T.J. Crowder
But then Abc(4, 5, 6) !== Abc(4, 5, 6)
. Using Abc.constructor = class Abc$ {}
and then returning Abc.constructor
won't make it work.
It can still be made to work...
const Abc = (function() {
const cache = new Map;
function readCache(c, arg, val=new Map) {
if (!c.has(a))
c.set(a, val);
return c.get(arg);
}
return (a, b, c) => {
// ...optionally do something with a, b, and c...
// Return a class
let retval = class Abc$ {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
// ...optionally do something with a, b, and c...
show() {
console.log(`a = ${a}, b = ${b}, c = ${c}`);
console.log(`x = ${this.x}, y = ${this.y}, z = ${this.z}`);
}
};
return readCache(readCache(readCache(cache, a), b), c, retval);
};
})();
const obj = new (Abc(4, 5, 6))(1, 2, 3);
obj.show();
Now Abc(4, 5, 6) === Abc(4, 5, 6)
.
See: CreatorVilius/ecmascript-proposals/blob/master/proposal-class-templates.md
I think having Class Templates in JavaScript would be awesome thing and should be implemented. This could be useful in a lot of cases. I know that mostly Statically typed languages have templates, but JS could also have Templates. It's not strict that you need to have Statically typed language in order to have Class Templates.