Do Maximally Minimal classes carry their weight?

# Allen Wirfs-Brock (12 years ago)

At the recent TC39 meeting a couple people raised the concern that maximally minimal class definitions 1 don't really do anything that isn't also possible with enhanced object literals 2 and hence the additional complexity they add to the language is undesirable. Only one of these alternatives should be in the language and enhanced object literals are preferable because they are compositional primitives that can be used to create a variety of higher level abstractions.

The counter argument is that max-min class definitions and enhanced obj lits support different use cases and that both are important. The class definitions present a more complete abstraction that exposes the class model already latent in the ES built-in objects. Even though max-min classes don't have all possible class bells and whistles they are a good "80%" solution that will likely to widely used and will facilitate code usage that crosses developer and library boundaries. Enhanced object literals are independently useful as compositional primitive and can be also be used to augment the capabilities of max-min class definitions.

To make this debate more concrete, I've created new versions of my Smalltalk-style collections class library 3 that use Max-min class definitions. These new versions also use arrow functions and I've added a version of the object literal based base-line that also uses arrow functions. Comparing these versions are a good way see the differences (and similarities) between the max-min classes and obj lit approaches to defining object abstractions in ES6.

The new files are: ST80collections-exp11.js 4: This is the base line that uses the <| and .{} pattern to defines "classes". ST80collections-exp10.js 5: Shows basic use of max-min classes declarations. It uses Object.defineMethod to define class methods. ST80collections-exp9.js 6: Shows max-min classes declarations with .{} used to define class methods and per instance properties.

Comparing either exp9 or exp10 to exp11 shows how max-min classes differ from just using extended object literals. Comparing exp9 to exp10 shows how .{} can pleasantly augment max-min class definitions in support of uses cases that they do not directly support.

What do you think? Assuming that we will have some forms of enhanced object literals in ES6, are max-min classes also worth the additional complexity they add to the language?

Allen

# Herby Vojčík (12 years ago)

Allen Wirfs-Brock wrote:

At the recent TC39 meeting a couple people raised the concern that maximally minimal class definitions [1] don't really do anything that isn't also possible with enhanced object literals [2] and hence the additional complexity they add to the language is undesirable. Only one of these alternatives should be in the language and enhanced object literals are preferable because they are compositional primitives that can be used to create a variety of higher level abstractions.

The counter argument is that max-min class definitions and enhanced obj lits support different use cases and that both are important. The class definitions present a more complete abstraction that exposes the class model already latent in the ES built-in objects. Even though max-min classes don't have all possible class bells and whistles they are a good "80%" solution that will likely to widely used and will facilitate code usage that crosses developer and library boundaries. Enhanced object literals are independently useful as compositional primitive and can be also be used to augment the capabilities of max-min class definitions.

To make this debate more concrete, I've created new versions of my Smalltalk-style collections class library [3] that use Max-min class definitions. These new versions also use arrow functions and I've added a version of the object literal based base-line that also uses arrow functions. Comparing these versions are a good way see the differences (and similarities) between the max-min classes and obj lit approaches to defining object abstractions in ES6.

The new files are: ST80collections-exp11.js [4]: This is the base line that uses the <| and .{} pattern to defines "classes". ST80collections-exp10.js [5]: Shows basic use of max-min classes declarations. It uses Object.defineMethod to define class methods. ST80collections-exp9.js [6]: Shows max-min classes declarations with .{} used to define class methods and per instance properties.

Comparing either exp9 or exp10 to exp11 shows how max-min classes differ from just using extended object literals. Comparing exp9 to exp10 shows how .{} can pleasantly augment max-min class definitions in support of uses cases that they do not directly support.

What do you think? Assuming that we will have some forms of enhanced object literals in ES6, are max-min classes also worth the additional complexity they add to the language?

I do not think they add too much complexity, but after looking at the examples I think they are not needed - the }.prototype.{ and }.constructor.{ are sort-of nice starters of "instance" and "class" part of method definitions - they can even be seen as magic "section starters" until understood that they are in fact normal language constructs.

It is even less needed if 'extends' would be added to functions to create double chain and <| left to create single chain - I sort of asked myself in the AbstractClass <| function .... }.prototype.{ ... where the prototype gets its parent from. I already read <| as single-chain only operator.

# Domenic Denicola (12 years ago)

To me, it is amazing how much clearer maximally-minimal classes make this code.

The <| function(){, }.prototype.{, and }.constructor.{ incantations in 4 are almost completely opaque, as is the reason behind needing Function.prototype as the lhs of <| for AbstractClass. They put the focus entirely on the crazy mechanics involved in emulating “classes” in JavaScript’s prototypal system, making you think about all the magic baked into constructor functions, the prototype property, the .prototype.constructor property, and how inheritance must be set up.

In contrast, I think 6 expresses the programmer intent exactly, at least so far as maximally-minimal classes allow. (Which is to say, private names are still done via arcane incantations.) And it relegates the .{ operator to a very understandable role: adding multiple properties at the same time.

Perhaps it is so much understandable because .{ never appears “sandwiched,” i.e. you never see }.property.{, only something.{. The former involves some mental juggling as you recall what exactly was just closed with }, and what magical semantics property has, and thus what the result of extending whateverWasJustClosed.magicalProperty will be.

Another nice aspect is that it reduces use of the <| operator, which does stuff that is nontrivial to correlate with a conventional notion of subclassing. Adding maximally-minimal classes, with extends, would relegate <| to the specialized use cases of people who know exactly what they’re doing, e.g. those who like to work with exemplars. Which is, IMO, exactly where it belongs.

In closing, I think these examples are an extremely strong argument for maximally-minimal classes. They give ES6 programmers the means to express what they mean, not what the language is contorting them into using. Without maximally-minimal classes, ES6 just gives us the means to express class patterns in an even-more-cryptic shorthand. With them, programmer intent shines through.

From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Allen Wirfs-Brock Sent: Saturday, March 31, 2012 13:41 To: Allen Wirfs-Brock Cc: es-discuss discussion Subject: Do Maximally Minimal classes carry their weight?

At the recent TC39 meeting a couple people raised the concern that maximally minimal class definitions 1 don't really do anything that isn't also possible with enhanced object literals 2 and hence the additional complexity they add to the language is undesirable. Only one of these alternatives should be in the language and enhanced object literals are preferable because they are compositional primitives that can be used to create a variety of higher level abstractions.

The counter argument is that max-min class definitions and enhanced obj lits support different use cases and that both are important. The class definitions present a more complete abstraction that exposes the class model already latent in the ES built-in objects. Even though max-min classes don't have all possible class bells and whistles they are a good "80%" solution that will likely to widely used and will facilitate code usage that crosses developer and library boundaries. Enhanced object literals are independently useful as compositional primitive and can be also be used to augment the capabilities of max-min class definitions.

To make this debate more concrete, I've created new versions of my Smalltalk-style collections class library 3 that use Max-min class definitions. These new versions also use arrow functions and I've added a version of the object literal based base-line that also uses arrow functions. Comparing these versions are a good way see the differences (and similarities) between the max-min classes and obj lit approaches to defining object abstractions in ES6.

The new files are: ST80collections-exp11.js 4: This is the base line that uses the <| and .{} pattern to defines "classes". ST80collections-exp10.js 5: Shows basic use of max-min classes declarations. It uses Object.defineMethod to define class methods. ST80collections-exp9.js 6: Shows max-min classes declarations with .{} used to define class methods and per instance properties.

Comparing either exp9 or exp10 to exp11 shows how max-min classes differ from just using extended object literals. Comparing exp9 to exp10 shows how .{} can pleasantly augment max-min class definitions in support of uses cases that they do not directly support.

What do you think? Assuming that we will have some forms of enhanced object literals in ES6, are max-min classes also worth the additional complexity they add to the language?

Allen

# Domenic Denicola (12 years ago)

As a quick follow-up:

Perhaps adding non-arcane-incantation private name declarations would be enough to push maximally-minimal classes from “nice, but are they worth it?” to “this gives us something we can’t get anywhere else.” To wit:

class Set extends Collection { private setContents, setTally

constructor(initialSize = 2) {
    this.{
        @setContents: new Array(initialSize),
        @setTally: 0
    }
}

// ...

}

# Kevin Smith (12 years ago)

Allen,

Thanks for this work - it's definitely helpful to see something concrete. I agree with Domenic that classes seem to communicate the intent more purely.

I also think that we're not quite there yet with respect to our class proposal. We have something that we all (more or less) agree on, sure. But I still feel like there's something missing. Not necessarily a feature - more of a philosophy... Still thinking...

# Axel Rauschmayer (12 years ago)

On Mar 31, 2012, at 19:40 , Allen Wirfs-Brock wrote:

Even though max-min classes don't have all possible class bells and whistles they are a good "80%" solution that will likely to widely used and will facilitate code usage that crosses developer and library boundaries.

That, to me, is the main argument in favor of mm classes. I don’t see any other mid- to short-term solution having that (urgently needed) effect. The boundary-crossing is also necessary for good IDE support.

# Allen Wirfs-Brock (12 years ago)

On Mar 31, 2012, at 5:19 PM, Domenic Denicola wrote:

As a quick follow-up:

Perhaps adding non-arcane-incantation private name declarations would be enough to push maximally-minimal classes from “nice, but are they worth it?” to “this gives us something we can’t get anywhere else.” To wit:

class Set extends Collection { private setContents, setTally

constructor(initialSize = 2) { this.{ @setContents: new Array(initialSize), @setTally: 0 } }

// ... }

Using a private declaration to define privateName bindings is still on the table. I just didn't show it in these example. However, it would most likely go outside of the class declarations:

private setContents, setTally;

class Set extends Collection {

constructor(initialSize = 2) { this.{ @setContents: new Array(initialSize), @setTally: 0 } }

// ... }

# Brendan Eich (12 years ago)

Why would it go outside? "Because we don't allow it inside" is not the reason, I hope.

It would be better -- if it were not a "friend" private among classes

# Russell Leggett (12 years ago)

When I started the "Safety Syntax" thread which let to the max-min proposal, I really did hope that we would still be able to slip some more features in for ES6, I just wanted to make sure we had something, even if it had to be max-min. I wanted to try to start with a useful baseline as fallback, so that we could continue to try to find consensus on more controversial features without fear of having no classes at all.

I think min-max has been really successful, and at least we can say that there's nothing left to take out. If the last stragglers holding it back fear that it is too minimal, maybe now is the time to carefully try to find something to put it over the top for those in doubt. Max-min has not reached a consensus, but it seems to at least gotten agreement that aside from some bikeshedding, it all belongs in classes i.e. there is nothing which needs to be removed/substantially changed.

If we were to try to take the smallest baby step forward, I think it should be private names inside of a class. Private names seem like a pretty solid feature. There still seems to be some room on the syntax - private keyword for example, but overall seems pretty accepted. That makes it pretty solid ground, because adding it to classes would mostly be another piece of sugar to help bring the common parts together. Private names are a really great building block, but using private names in classes is going to be a really major use case for them, so I think it would be a pretty short leap to bring them together.

As Domenic said, perhaps it would bring things over the top. There are a lot of new features in ES6. The <| operator (allowing extension/super), and private name objects are two features which are made more flexible by being stand-alone, but are perhaps a little low-level for the tastes of many mainstream developers. Max-min classes + class-scoped private names would be a way of tying in these new features, hitting the really common use case, but also formalizing a syntax for a pattern which has been around since the beginning. It is way of wrapping up the old and the new into a package which feels familiar, and should be easy to use/read/understand for new and old JS devs. I think it would be hard to say that proposal is "too little". The rest of the argument would still stand. It would still be fairly minimal and would hopefully still leave plenty of room for additional features.

# Herby Vojčík (12 years ago)

Russell Leggett wrote:

When I started the "Safety Syntax" thread which let to the max-min proposal, I really did hope that we would still be able to slip some more features in for ES6, I just wanted to make sure we had something, even if it had to be max-min. I wanted to try to start with a useful baseline as fallback, so that we could continue to try to find consensus on more controversial features without fear of having no classes at all.

I think min-max has been really successful, and at least we can say that there's nothing left to take out. If the last stragglers holding it back fear that it is too minimal, maybe now is the time to carefully try to find something to put it over the top for those in doubt. Max-min has not reached a consensus, but it seems to at least gotten agreement that aside from some bikeshedding, it all belongs in classes i.e. there is nothing which needs to be removed/substantially changed.

If we were to try to take the smallest baby step forward, I think it should be private names inside of a class. Private names seem like a pretty solid feature. There still seems to be some room on the syntax - private keyword for example, but overall seems pretty accepted. That makes it pretty solid ground, because adding it to classes would mostly be another piece of sugar to help bring the common parts together. Private names are a really great building block, but using private names in classes is going to be a really major use case for them, so I think it would be a pretty short leap to bring them together.

As Domenic said, perhaps it would bring things over the top. There are a lot of new features in ES6. The <| operator (allowing extension/super), and private name objects are two features which are made more flexible by being stand-alone, but are perhaps a little low-level for the tastes of many mainstream developers. Max-min classes + class-scoped private names would be a way of tying in these new features, hitting the really common use case, but also formalizing a syntax for a pattern which has been around since the beginning. It is way of wrapping up the old and the new into a package which feels familiar, and should be easy to use/read/understand for new and old JS devs. I think it would be hard to say that proposal is "too little". The rest of the argument would still stand. It would still be fairly minimal and would hopefully still leave plenty of room for additional features.

Max-min classes were presented as the thing that does not prevent class evolution in "more object-initializer-like-way" (it is already unfriendly in making it object-initializer-syntactically bercause of comma-elision, but semantically it still can be) as well as other ways. Adding private names into class block may be the thing that stops this future friendliness.

It depends on one little detail. Does this code:

function make () { return new class { private x; constructor (x) { this. at x = "foo"; } xOf (o) { return o. at x; } }; }

let obj = make(); console.log(make().xOf(obj));

print out "undefined" or "foo"?

If you agree that it prints out undefined, I will agree with private in classes. If you claim it should print out "foo", I'll say no to this-way-defined private inside class block.

Of course, this prints "foo" (the previous example is about independently created class expressions):

class FooHolder { private x; constructor (x) { this. at x = "foo"; } xOf (o) { return o. at x; } };

let obj = new FooHolder; console.log(new FooHolder().xOf(obj));

The bottom line is: there is already movement to have "private x" in the language, as the shortcut to locally* define x as Name.create(). If 'private x' added to classes will follow this semantics (so it is deifferent for different invocations of class expression, but still the same for (the same) declared class (or for the instances of the same class expression), I will accept it; but I will raise my hand against if it would have different semantics.

  • Russ

Herby

  • P.S.: I don't like it, I would rather see 'private x' as 'define static shared one over multiple invocations', but no one liked it that way, so I accepted 'shortcut to let' semantics; nevertheless, I want it to be everywhere consistently.
# Kevin Smith (12 years ago)

We can see from the examples that Allen posted that two features are used in virtually every class definition: a mechanism for carrying "private" instance state, and properties attached to the constructor itself ("static" members, if you'll pardon the misnomer).

I'm currently thinking that there are some issues with how we are currently implementing private state using private names. I'll post sometime this week with my thoughts.

# Allen Wirfs-Brock (12 years ago)

On Mar 31, 2012, at 9:54 PM, Russell Leggett wrote:

When I started the "Safety Syntax" thread which let to the max-min proposal, I really did hope that we would still be able to slip some more features in for ES6, I just wanted to make sure we had something, even if it had to be max-min. I wanted to try to start with a useful baseline as fallback, so that we could continue to try to find consensus on more controversial features without fear of having no classes at all.

I think min-max has been really successful, and at least we can say that there's nothing left to take out. If the last stragglers holding it back fear that it is too minimal, maybe now is the time to carefully try to find something to put it over the top for those in doubt. Max-min has not reached a consensus, but it seems to at least gotten agreement that aside from some bikeshedding, it all belongs in classes i.e. there is nothing which needs to be removed/substantially changed.

Agreed, but we need to me really careful to not slip into controversy mode about additional features. If that happens, it isn't clear that the recovery would be back to baseline max-min classes. It could go back to no class declarations at all.

If we were to try to take the smallest baby step forward, I think it should be private names inside of a class. Private names seem like a pretty solid feature. There still seems to be some room on the syntax - private keyword for example, but overall seems pretty accepted. That makes it pretty solid ground, because adding it to classes would mostly be another piece of sugar to help bring the common parts together. Private names are a really great building block, but using private names in classes is going to be a really major use case for them, so I think it would be a pretty short leap to bring them together.

I think we need private outside of class declarations to cover all of the use cases (including those that aren't tied to classes).

I'd also be happy with private as a ClassElement that is lexically scoped to a ClassBody.

However, when we add private as a ClassElement we have crossed the line to having things other PropertyMethodDefinition in ClassBody. If this opens the flood gates for every over possible addition we will be back in the swamp.

We just need to be really careful to not get lost as we work toward final consensus on class definitions

# Brendan Eich (12 years ago)

Allen Wirfs-Brock wrote:

However, when we add private as a ClassElement we have crossed the line to having things other PropertyMethodDefinition in ClassBody. If this opens the flood gates for every over possible addition we will be back in the swamp.

I like your message, except for this metaphor. We're in charge of the syntax. It's not an overflowing river surging against our gates. We can say "no" and do. I think we've just gone a little too far, without explicit and rationalized "no" so much as preemptive minimization to get consensus.

My favorite trope is the game of Jenga. We must not stack too high. But some pieces really need other pieces under or next to them. "private x" is one such affordance, and we've heard already that if ES6 requires

const px = Name.create(), py = Name.create(), pz = Name.create();

we'll have failed to make private names usable in some contexts

# Allen Wirfs-Brock (12 years ago)

On Apr 1, 2012, at 2:58 AM, Herby Vojčík wrote:

...

Max-min classes were presented as the thing that does not prevent class evolution in "more object-initializer-like-way" (it is already unfriendly in making it object-initializer-syntactically bercause of comma-elision, but semantically it still can be) as well as other ways. Adding private names into class block may be the thing that stops this future friendliness.

It depends on one little detail. Does this code:

function make () { return new class { private x; constructor (x) { this. at x = "foo"; } xOf (o) { return o. at x; } }; }

let obj = make(); console.log(make().xOf(obj));

print out "undefined" or "foo"?

If you agree that it prints out undefined, I will agree with private in classes. If you claim it should print out "foo", I'll say no to this-way-defined private inside class block.

According to my assumptions it would print "undefined". The intent for private outside of a class declaration is that it would simply be sugar for: const id = Name.create(); and that within a ClassBody it has the same semantics, except that it is lexically scoped to the ClassBody. That means each evaluation of a class definition gets a new instance of the lexically scoped private name id that is initialized to a new private name value. So each: new class{ } is creating a new binding and value for x and each object returned from make will have a different private named property key for x.

Of course, this prints "foo" (the previous example is about independently created class expressions):

class FooHolder { private x; constructor (x) { this. at x = "foo"; } xOf (o) { return o. at x; } };

let obj = new FooHolder; console.log(new FooHolder().xOf(obj));

The bottom line is: there is already movement to have "private x" in the language, as the shortcut to locally* define x as Name.create(). If 'private x' added to classes will follow this semantics (so it is deifferent for different invocations of class expression, but still the same for (the same) declared class (or for the instances of the same class expression), I will accept it; but I will raise my hand against if it would have different semantics.

Exactly.

# Erik Arvidsson (12 years ago)

The main issue you will see if you do user studies on people trying to do OOP in JS is that the way to set up the prototype chain in ES3/5 is too hard. There is a reason why almost all JS libraries add ways to make this easier.

With the "let C = B <| function() { ... }.prototype.{ ... }.constructor" pattern we are making the default pattern even harder to understand. Expecting people to get this is just too much to ask for.

On Sat, Mar 31, 2012 at 10:40, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

What do you think?  Assuming that we will have some forms of enhanced object literals in ES6, are max-min classes also worth the additional complexity they add to the language?

I think the code samples shows how much a dedicated class syntax can reduce the complexity, improves the readability and the intent of the code.

Classes is a clear case of "Say what you mean!" whereas the let-triangle-function-prototype-monocle-mustache-constructor pattern is more like "I know how the internals work" which is hardly something we should be pushing for.

# Tab Atkins Jr. (12 years ago)

On Mon, Apr 2, 2012 at 2:39 PM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:

The main issue you will see if you do user studies on people trying to do OOP in JS is that the way to set up the prototype chain in ES3/5 is too hard. There is a reason why almost all JS libraries add ways to make this easier.

With the "let C = B <| function() { ... }.prototype.{ ... }.constructor" pattern we are making the default pattern even harder to understand. Expecting people to get this is just too much to ask for.

On Sat, Mar 31, 2012 at 10:40, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

What do you think?  Assuming that we will have some forms of enhanced object literals in ES6, are max-min classes also worth the additional complexity they add to the language?

I think the code samples shows how much a dedicated class syntax can reduce the complexity, improves the readability and the intent of the code.

Classes is a clear case of "Say what you mean!" whereas the let-triangle-function-prototype-monocle-mustache-constructor pattern is more like "I know how the internals work" which is hardly something we should be pushing for.

Strongly agreed.

I don't have any particular problem with the current ES3-style classes, except that they're verbose to write and difficult to read. Their structure doesn't speak to you when reading it; you have to figure out for yourself what the right pattern is and how to recognize it in code.

The maximal-minimal classes fix this by making the pattern simple to write and obvious to read. You see a "class" block, you know the contents are defining methods on the prototype. Simple! Actually writing it out is simpler, too, because you get to avoid all that silly "foo.prototype.bar = function (...){...}" business in favor of a simple "function bar(...){...}". (I cannot tell you how many times I've had to correct a syntax error when I wrote "foo.prototype.bar(...){...}" instead... I do this at least once per project.)

Like Erik said, utilizing the new proto-of and dot-brace primitives to make the verbosity somewhat smaller isn't much of a win. You drop some characters, but replace them with relatively opaque syntax, rather than clear syntax. It still requires you to learn the precise details of the "correct" JS class model, which, though decently designed imo, is still rather confusing. Further, the dangling ".constructor" at the end is just nasty, since it's a new requirement of this "one big expression" syntax, and wasn't necessary when classes were just a big bag of statements. There's little or no net gain here.

Giving people easy, direct access to primitives is great. It's a requirement for real hacking in the language, and it often enables interesting patterns that were never originally intended. But that doesn't invalidate the need for new high-level abstractions as well. Maximal-minimal classes are a well-designed high-level abstraction here. They succinctly replace what was previously a hard-to-read markup pattern. The net gain is still relatively small right now, but still noticeable, and they're friendly to future extensions that magnify the gain over unadulterated base primitives.

# John J Barton (12 years ago)

Allen's original post on this thread offered two choices:

  1. extended object literals, (good building blocks).
  2. both, (because class gives 80% and thus they complement). Erik and Tab are arguing for
  3. Min-max classes (we need 80%, not building blocks). The current winner no one wants:
  4. do nothing.

Allen's large examples illustrates one point for me: the class syntax differences are not very big, compared to the other changes.

One important question for me: can the results of class syntax be used as building blocks without the object-literal extensions? I mean: can the objects built from class syntax be used meta-programming even if they are (deliberately) not prefect tools for that purpose? Can the solution for 80% help with the last 20% or at least no hinder?

I know this may be a difficult question to answer...

jjb

# Allen Wirfs-Brock (12 years ago)

On Apr 2, 2012, at 5:00 PM, John J Barton wrote:

Allen's original post on this thread offered two choices:

  1. extended object literals, (good building blocks).
  2. both, (because class gives 80% and thus they complement). Erik and Tab are arguing for
  3. Min-max classes (we need 80%, not building blocks). The current winner no one wants:
  4. do nothing.

Allen's large examples illustrates one point for me: the class syntax differences are not very big, compared to the other changes.

but the class syntax maybe what is needed to standardize a baseline class model.

One important question for me: can the results of class syntax be used as building blocks without the object-literal extensions? I mean: can the objects built from class syntax be used meta-programming even if they are (deliberately) not prefect tools for that purpose? Can the solution for 80% help with the last 20% or at least no hinder?

I have a couple thoughts

The "superclass" expression provides useful extension point:

class foo extends Mixin(bar, trait1,trait2,trait3} { constructor() {} method1() {} }

In the above example you can think of Mixin as a higher order class that generates the actual "superclass".

It may also be useful to define class initialization as calling invoking a method on the "superclass" after the subclass has been constructed but before its value is bound. EG:

  class foo extends expr {constructor() {} }

initializes as: const foo = expr. at initializeSubclass(<new constructor object with initialized prototype>);

This would give superclasses significant control over the initialization of subclasses allowing things such as injecting additional properties, setting property attributes, etc.

Finally, if you want to create more elaborate class abstractions I think you would want to parameterize them using object literals rather than class expressions:

let Thing = JJBClass({ primarySuper: Entity, mixins: [a,b,c], constructor() {}, instanceMethods: { method1() {} method2(){} }, classMetods: { cmethod1() {} cmethod2(){} } };

rather than:

let Thing = JJBClass({ base: class extends Entity { constructor() {} method1() {} method2(){} }, mixins: [a,b,c], classMetods: class { //these get copied to constructor cmethod1() {} cmethod2(){} } };

Alen