├── ES7MetaProps.md ├── Generator metaproperty.md ├── LICENSE ├── dcltomethod.md └── simdAlt.js /ES7MetaProps.md: -------------------------------------------------------------------------------- 1 | ## Additional Meta Properties for ES7 ## 2 | Allen Wirfs-Brock 3 | February 26, 2015 4 | 5 | ### The Problem and Opportunity 6 | The ES community occasionally identifies contextually variable run-time values that would be useful if they could be accessed from ES code. The problem is that we have had no common way to approach making such values available. The space of available keywords and operator symbols that might be associated with such values is severely limited. Associating them with lexical bindings is also unattractive. The result, is that TC39 has steered away from adding support for accessing such values. 7 | 8 | However, recently ES6 added the syntatic concept of a *MetaProperty*. Syntactically a *MetaProperty* is a pre-existing reserved word followed by a period and then an *IdentifierName*. For example: `for.sake`. The reserved word must be one that the ES grammar does not permit to be otherwise immediately followed by a period. 9 | 10 | ES6 defined only one *MetaProperty*, `new.target`. However, this establishes a syntactic pattern that could be applied for accessing other contextually variable run-time values. For ES7 we should review the set of such values that we know about and considering adding additional meta properties for accessing them. 11 | ### Candidate Meta Properties 12 | 13 | ####`function.callee` -- The currently running function 14 | #####Value and Context 15 | The value of `function.callee` is the function object that is currently being evaluated by the running execution context. It is *not* lexically scoped like `this`, `super` or `new.target`. Its value may be an Arrow Function. 16 | 17 | Referencing `function.callee` outside of function code is a Syntax Error. 18 | 19 | #####Use Cases 20 | Anonymous functions, arrow functions, and concise methods with non-identifier property names sometimes need to recursively refer to themselves. Prior to ES5 the currently executing function object was available via `arguments.callee` but that is now unavailable in strict mode functions. In addition, within arrow functions, `argument` is lexically scoped to the closest containing non-arrow function. 21 | 22 | ####`function.count` -- The actual argument count 23 | #####Value and Context 24 | The value of `function.count` is the actual number of arguments pass to the function that is currently being evaluated by the running execution context. It is *not* lexically scoped like `arguments` so it can report the number of arguments passed to an Arrow Function. 25 | 26 | Referencing `function.count` outside of function code is a Syntax Error. 27 | 28 | #####Use Cases 29 | Even with the availability of parameter default values and rest parameters it is sometimes useful to know the actual number of arguments passed to a function invocation. For example, to help resolve argument overloads. The only currently available way to get the actual argument count that will work for any function is to declare the function with a single rest parameter, for example: 30 | ```es6 31 | (...args)=>console.log(args.length) 32 | ``` 33 | The use of this technique precludes use of a more meaningful parameter signature and forces instantiation of an array containing the argument values even if the only information needed is the argument count. 34 | 35 | ####`function.arguments` -- The actual argument list 36 | #####Value and Context 37 | The value of `function.arguments` is an array containing the actual arguments passed to the function that is currently being evaluated by the running execution context. It is *not* lexically scoped like `arguments` so it can provide the actual arguments passed to an Arrow Function. It is essentially the same as the value that is assigned to `args` for a parameter list of the form `(...args)`. 38 | 39 | Each time `function.arguments` is evaluated it returns a fresh array. 40 | 41 | Referencing `function.arguments` outside of function code is a Syntax Error. 42 | 43 | #####Use Cases 44 | `function.arguments` is essentially a replacement for the legacy `arguments` object that doesn't carry any of the baggage of `arguments` and which can be used with all function forms including Arrow Functions and in all modes. Uses include declaring a function with a meaningful parameter signature while still having the original arguments available if an overload conditions requires delegation of the arguments to another function.. 45 | 46 | 47 | #### Module Meta Data 48 | Meta Properties may be useful for providing access to various meta data associated with a module. If desired, proposals for such properties need to be added here by the module champions. 49 | -------------------------------------------------------------------------------- /Generator metaproperty.md: -------------------------------------------------------------------------------- 1 | ## Generator function.sent Meta Property ## 2 | Allen Wirfs-Brock 3 | May 13, 2015 4 | 5 | ### The Problem 6 | When the `next` method is invoked on a generator objects, the value passed as the first argument to `next` is "sent" to the generator object and becomes available within the body of the generator function as the value of the `yield` expression that most recently suspended the generator function. This supports two-way communications between the a generator object and its consumer. 7 | 8 | However, the first `next` that a generator's consumer invokes to start a generator object does not correspond to any `yield` within the body of the generator function. Instead, the first `next` simply causes execution of the generator function body to begin at the top of the body. 9 | 10 | Because there the first `next` call does not correspond to a `yield` within the generator function body there is currently no way for the code with the body to access the initial `next` argument. For example: 11 | 12 | ```js 13 | function *adder(total=0) { 14 | let increment=1; 15 | while (true) { 16 | switch (request = yield total += increment) { 17 | case undefined: break; 18 | case "done": return total; 19 | default: increment = Number(request); 20 | } 21 | } 22 | } 23 | 24 | let tally = adder(); 25 | tally.next(0.1); // argument will be ignored 26 | tally.next(0.1); 27 | tally.next(0.1); 28 | let last=tally.next("done"); 29 | console.log(last.value); //1.2 instead of 0.3 30 | ``` 31 | In the above example, the argument to the `next` method normally supplies the value to added to a running tally. Except that the increment value supplied to the first next is ignored. 32 | 33 | This proposal provides an alternative way to access the `next` parameter that works on the first and all subsequent invocations of a generator's `next` method. 34 | ### The Proposal 35 | 36 | ###A new meta-property: `function.sent` 37 | #####Value and Context 38 | The value of `function.sent` within the body of a Generator Function is the value passed to the generator by the `next` method that most recently resumed execution of the generator. In particular, referencing `function.sent` prior to the first evaluation of a `yield` operator returns the argument value passed by the `next` call that started evaluation of the *GeneratorBody*. 39 | 40 | `function.sent` can appear anywhere a *YieldExpress* would be legal. Referencing `function.sent` outside of a *GeneratorBody* is a Syntax Error. 41 | #####Usage Example 42 | Here is how the above example might be rewritten using `function.sent` 43 | ```js 44 | function *adder(total=0) { 45 | let increment=1; 46 | do { 47 | switch (request = function.sent){ 48 | case undefined: break; 49 | case "done": return total; 50 | default: increment = Number(request); 51 | } 52 | yield total += increment; 53 | } while (true) 54 | } 55 | 56 | let tally = adder(); 57 | tally.next(0.1); // argument no longer ignored 58 | tally.next(0.1); 59 | tally.next(0.1); 60 | let last=tally.next("done"); 61 | console.log(last.value); //0.3 62 | ``` 63 | 64 | ###Specification Updates 65 | The following are deltas to the ECMAScript 2015 Language Specification 66 | #### 8.3 Execution Contests 67 | The following row is added to **Table 24**:
68 | 69 | | Component | Description 70 | |------------------|------------------------------------------------------------------- 71 | | LastYieldValue | The value of the most recently evaluated *YieldExpression* 72 | 73 | #### 12.3 Left-Hand-Side Expression 74 | ##### Syntax 75 | 76 | *MemberExpression*[Yield]  :
77 |             ...
78 |             *MetaProperty*[?Yield]
79 |             ... 80 | 81 | *MetaProperty*[Yield]  :
82 |             *NewTarget*
83 |              [+Yield] *FunctionSent* 84 | 85 | #### 14.4 Generator Function Definitions 86 | ##### Syntax 87 | *FunctionSent*  :
88 |             **function . sent** 89 | #### 14.4.14 Evaluation 90 | *FunctionSent* : **function . sent**
91 |     1.  Assert: the running execution context is a Generator Context.
92 |     2.  Let *genContext* be the running execution context.
93 |     3.  Return the value of the LastYieldValue component of *genContext* .
94 | #### 25.3.3.1 GeneratorStart(generator, generatorBody) 95 | 96 | Between lines 3 and 4 of the ES6 algorithm add the following step: 97 | 98 |     3.5.  Set the LastYieldValue component of *genContext* to **undefined**. 99 | 100 | #### 25.3.3.3 GeneratorResume(generator, value) 101 | Between lines 8 and 9 of the ES6 algorithm add the following step: 102 | 103 |     8.5.  Set the LastYieldValue component of *genContext* to *value*. 104 | 105 | #### 25.3.3.5 GeneratorYield(iterNextObj) 106 | Between lines 5 and 6 of the ES6 algorithm add the following step: 107 | 108 |     5.5.  Set the LastYieldValue component of *genContext* to **undefined**. 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /dcltomethod.md: -------------------------------------------------------------------------------- 1 | ## A Declarative Alternative to toMethod ## 2 | Allen Wirfs-Brock 3 | February 23, 2015 4 | 5 | ### The Problem 6 | **TL;DR The Semantics of ES6 `super` clashes with ad hoc method mixins** 7 | 8 | ECMAScript 2015 provides the `super` keyword for delegating property accesses to a property definition provided further up the prototype (or superclass) inheritance chain. For example: 9 | ```es 10 | class MyArray extends Array { 11 | push(...args) { 12 | console.log(`pushing ${args)`); 13 | super.push(...args); 14 | } 15 | } 16 | ``` 17 | In order for the function `MyArray.prototype.push` to be able to find the `Array.prototype.push` method, the function needs to keeps a reference to the object that holds it as an own property. That reference is called the function's [[HomeObject]]. In this example function's [[HomeObject]] value is `MyArray.prototype`. 18 | 19 | JavaScript programmers are used to installing methods on objects by simply assigning a function as the value of a property. So, a programmer might reasonably expect that the `MyArray.prototype.push` method could be associated with another objects via an assignment like: 20 | ```js 21 | someObject.push = MyArray.prototype.push; 22 | ``` 23 | But, because of the [[HomeObject]] method association this usually will not have the intended result. For example, consider: 24 | ```js 25 | //Example 1 26 | class Pusher { 27 | push(...args) { 28 | console.log(`Pusher.prototype.push`); 29 | Array.prototype.push.apply(this, args); 30 | } 31 | } 32 | let aPusher = new Pusher; 33 | aPusher.push(0); //console: Pusher.protoype.push 34 | aPusher.push = MyArray.prototype.push //ad hoc mixin 35 | 36 | aPusher.push(1); //console: pushing 1 37 | //expected: pushing 1 38 | // Pusher.prototype.push 39 | ``` 40 | A programmer who wrote the assignment `aPusher.push = MyArray.prototype.push` was probably thinking that they could just reuse the `push` method from `MyArray.prototype` and that the `super.push` call within it would start searching for a `push` method at the [[Prototype]] of `aPusher`. But it doesn't. Instead that method will always begin its `super.push` search starting with the [[prototype]] of `MyArray.prototype` because that is what the [[HomeObject]] of the function is permanently set to. 41 | 42 | Using Object.assign with an object literal has similar counter-intuitive results: 43 | ```js 44 | //Exammple 2 45 | Object.assign(aPusher, { 46 | push(...args) { 47 | console.log("aPusher mixin"); 48 | super.push(...args); 49 | } 50 | } 51 | ``` 52 | In this case, the [[HomeObject]] of the mixed-in `push` function is set to the literally created object that is passed as the second argument to `Object.assign` rather than the object that is the value of `aPusher`. `super.push` will look for a `push` method in `Object.prototype` rather than in `Pusher.prototype` as was intended. Such a method probably won't be found. The same problem exists if a programmer tries to use `Object.assign` to mix methods into the prototype object created by a constructor function or class declaration 53 | 54 | In summary, in ES6 using property assignment or `Object.assign` to mix functions into objects (including prototype objects and constructors) results in unexpected problematic behavior if the functions contain any `super` property references. 55 | 56 | ### The toMethod Solution ### 57 | **TL;DR The draft ES6 `toMethod` solution was to set the [[HomeObjedt]] of a clone of the original method. That was solution was abandoned because it was unintuitive, complex, and error-prone.** 58 | 59 | The original approach tried in ES6 drafts was to use a built-in method named `toMethod` to solve this problem. ``toMethod` was defined as a method on `function.prototype` and could be used to change the [[HomeObject]] association of a function. 60 | 61 | For example, in example 1 the method mix-in assignment: 62 | ```js 63 | aPusher.push = MyArray.prototype.push //ad hoc mix-in 64 | ``` 65 | would have been replaced by: 66 | ```js 67 | aPusher.push = MyArray.prototype.push.toMethod(aPusher); 68 | ``` 69 | Conceptually, what `toMethod` does is set the [[HomeObject]] of its `this` object to the object passed as its argument and then return its updated `this` value. But it can't actually do that. The any preexisting references (from `MyArray.prototype` in this example) to the `this` value still exists. And those reference typically need to use the old [[HomeObject]] value rather than its new value. Changing [[HomeObject]] to `aPusher` would correctly set it for `aPusher` usage but would break it for `MyArray.prototype` usage. 70 | 71 | Instead, `toMethod` makes an almost clone of the function that is its `this` value and then returns the clone function as its value. One of the ways that the clone function is different from the original function is that its [[HomeObject]] is set to the `toMethod` argument. So, `MyArray.prototype.push.toMethod(aPusher)` creates a clone of the function that is the value of `MyArray.prototype.push`, then sets the clone's [[HomeObject]] to the value of `aPusher`, and finally it returns the clone. It is that clone value that is then assigned to `aPusher.push`. The original `MyArray.prototype.push` function is unmodified. 72 | 73 | However, cloning a function creates other complications. Is the clone a deep or shallow clone? In either case are all of the functions properties cloned or only some of them. If the function itself has function valued properties should `toMethod` be recursively applied to them with the clone as the argument? What happens if `toMethod` is applied to a built-in function, a bound function, or a callable Proxy object. Is it expected to also know how to clone those? 74 | 75 | The answer used in the ES6 draft version of `toMethod` was to perform a shallow clone of the function excluding all own properties except for `length`. If any other properties needed to be included in the clone (either shallowly or deeply) it was up to caller to `toMethod` to take care of that copying after `toMethod` returned the clone to it. For this reason, the ES6 draft `toMethod` was best thought of as a primitive that was intended to be primarily used by mix-in libraries or other abstractions over objects. Such libraries would have needed to establish their own policies for dealing with the cloning issue and for dealing with various kinds of exotic function objects. 76 | 77 | Ultimately, TC39 decided that `toMethod` was too complex and error-prone. 78 | ### Declarative Is Better 79 | As shown in the examples above, defining methods that reference `super` properties in class declarations is simple and straightforward. This is also true for object literals such as: 80 | ```js 81 | let dog = { 82 | __proto__: animal, 83 | walk() { 84 | this.wagTail(); 85 | super.walk() 86 | } 87 | } 88 | ``` 89 | The reason this works well is that a class definition or object literal declaratively associates a new `super` referencing function object with the the appropriate "home object". There is no need to manipulate the method outside the declaration, no need to imperatively modify a preexisting [[HomeObject]] reference, and no need to clone a method. 90 | 91 | Ideally, ECMAScrpt's support for ad hoc mix-ins should have these same characteristics. 92 | 93 | Remember Example 2: 94 | ```js 95 | //Exammple 2 96 | Object.assign(aPusher, { 97 | push(...args) { 98 | console.log("aPusher mixin"); 99 | super.push(...args); 100 | } 101 | } 102 | ``` 103 | It looked reasonable, but did the wrong thing. Here is what a declarative version that doesn't use `toMethod` but still does the correct thing might look like: 104 | ```js 105 | //Exammple 2 - declarative 106 | aPusher mixin { 107 | push(...args) { 108 | console.log("aPusher mixin"); 109 | super.push(...args); 110 | } 111 | }; 112 | ``` 113 | ###A Declarative Solution 114 | In this solution, `mixin` is a contextual keyword that is the first token of a high precedence left-associative postfix operator. The second part of a `mixin`operator has the syntax of an object literal and all of the normal property definition forms are allowed within it except for `__proto__:`. Note that the object literal is a integral part of the `mixin` postfix operator operator, not a separate sub expression. We call the value that the `mixin` operator is applied to the "augmented object". 115 | 116 | A simplified syntactic description of the `mixin` operator is: 117 | _MixinExpression_ : _MixinExpression_ `mixin` _ObjectLiteral_ 118 | where the value of the _MixinExpression_ to the left of the `mixin` contextual keyword is the augmented object. 119 | 120 | The semantics are almost exactly the same as a regular object literal except that the property definitions within the _ObjectLiteral_ define properties on the augmented object. Just like a normal `ObjectLiteral` the properties are defined using [[DefineOwnProperty]] and they set property attributes just like an `ObjectLiteral`. The value of the `mixin` object is the augmented object, after its properties have been updated. 121 | 122 | Any methods within the `ObjectLiteral` that need a [[HomeObject]] binding are created with the augment object as their [[HomeObject]] value. No method cloning is perform and a method with the "wrong" or `undefined` [[HomeObject]] never exists. 123 | 124 | **Note that it is a very important characteristic that this proposal that `mixin` is an operator**, rather than a function such as `Object.mixin` which was considered for ES6. Use of an operator allows the new methods to be initially instantiated using the correct [[HomeObject]] values. All function based approaches require initially instantiating functions with the wrong [[HomeObject]] values and this leads to the need to clone the functions. 125 | ####But What If You Need Imperative Mixins? 126 | The `mixin` operator solves the [[HomeObject]] binding problem by always defining the mixed-in methods at one place in a program so that the augmented object is available when the method function objects are instantiated. But what if you need to apply a mixin at many different places in a program? Just use procedural abstraction: 127 | ```es6 128 | //someMixin.js 129 | export const someMixin = obj=>obj mixin { 130 | method1() {return super.method1()}, 131 | Method2() {...}, 132 | data: 42 133 | }; 134 | ---------------------------------------- 135 | //consumer.js 136 | import {someMixin} from "someMixin.js"; 137 | let myObj = someMixin(new MyClass()); 138 | //... 139 | someFunct(someMixin(anotherObj)); 140 | //... 141 | ``` 142 | ####Augmenting Classes 143 | The mixin operator can be applied to any object, including class objects and constructor functions: 144 | ```es6 145 | class C extends B{ 146 | static sm1() {} 147 | m1() {} 148 | } 149 | 150 | C mixin { 151 | m2() {super.m2()} 152 | } 153 | ``` 154 | In the above example the augmented object is the class constructor `C` so `m2` will be added as a `static` method `C` and not as a method of `C.prototype`. The `super` property reference in `m2` follows the constructor prototype chaining starting at `B` rather than than the prototype chain of `C.prototype`. 155 | 156 | While this could be what somebody who wrote `C mixin {...}` intended, it probably isn't. More likely, when extending a class object, a developer really wants to default to adding properties to the class' prototype object and if they want to add `static` methods they would prefer to label them as such. 157 | 158 | There are other annoyances with using `mixin {...}` to augment class constructor objects. One is that the value of the [[Enumerable]] attribute that is set by an _ObjectLiteral_ is the opposite value from what is set for method definitions in a _ClassBody_. More generally when extending a class constructor you would like to be able to use _ClassBody_ syntax and semantics rather than _ObjectLiteral_ syntax and semantics. This is already an issue for `static` methods. In the future it is likely that other kinds of `ClassBody` elements will be added to ECMAScript and probably at least some of those should be available when augmenting a class constructor using the `mixin` operator. 159 | 160 | We can address these issues by providing a second form of the `mixin` operator that is specifically defined for augmenting constructor objects. The simplified syntactic description of this alternative `mixin` form is: 161 | _MixinExpression_ : _MixinExpression_ `mixin class { ` _ClassBody_ `}` 162 | 163 | The `class` keyword following `mixin` indicates that this is a class mixin operation rather than an object mixin operation. the `mixin class` operator first performs an IsConstructor test of the augmented object and throws a TypeError exception if the result is `false`. Otherwise, the non-static property definitions from _ClassBody_ are defined in the manner of a class definition on the value of the augmented object's `prototype` property and `static` property definitions are defined upon the argumented object itself. In both cases, each method's [[HomeObject]] is set appropriately. The only restriction on _ClassBody_ (assuming only ES6 level elements) is that it may not define a `constructor` method. 164 | 165 | Using a `mixin class` operator, the above example would be written like: 166 | 167 | ```es6 168 | C mixin class { 169 | m2() {super.m2()} 170 | } 171 | ``` 172 | and `m2` would be defined as a method property of `C.prototype`. If you wanted to augment both the prototype and the constructor you could write: 173 | 174 | ```es6 175 | C mixin class { 176 | m2() {super.m2()}; //[[HomeObject]] is C.prototype 177 | static sm2() {super.sm2()};//[[HomeObject]] is C 178 | } 179 | ``` 180 | ###None Goals 181 | This proposal is not intended to be a replacement for higher level class composition abstractions such as Traits. Instead it provides the essential primitive language capabilities which combined with procedural or object abstraction capabilities can be used to define such higher level compositional abstractions. 182 | ###BNF 183 | 184 | Here is the proposed BNF for this extension. 185 | 186 | ```bnf 187 | MixinExpression : 188 | LeftHandSideExpression 189 | MixinExpression 'mixin' [no LineTerminator here] ObjectLiteral 190 | MixinExpression 'mixin' [no LineTerminator here] 'class {' ClassBody '}' 191 | 192 | PostfixExpression : 193 | MixinExpression 194 | MixinExpression [no LineTerminator here] ++ 195 | MixinExpression [no LineTerminator here] -- 196 | ``` 197 | -------------------------------------------------------------------------------- /simdAlt.js: -------------------------------------------------------------------------------- 1 | //module SIMD -- with static methods for operations 2 | 3 | export class Float32x4 { 4 | constructor (v1, v2, v3, v4) { ...} 5 | 6 | //factory methods 7 | static splat(v) {return new this(v, v, v, v); 8 | static fromFloat64x2(t) {...} 9 | static fromInt32x4(t) {...} 10 | static fromFloat64x2Bits(t) {...} 11 | static fromInt32x4Bits(t) {...} 12 | static fromInt16x8Bits(t) {...} 13 | static fromInt8x16Bits(t) {...} 14 | 15 | //static predicates 16 | static check(v) {[[hasTag]](v, this) ? v : throw new TypeError} 17 | 18 | //static accessor function 19 | static extractLane(t, i) {...} 20 | static store(array, index, value) {...} 21 | static store1(array, index, value) {...} 22 | static store2(array, index, value) {...} 23 | static store3(array, index, value) {...} 24 | 25 | //computational factories 26 | static abs(t) {...} 27 | static neg(t) {...} 28 | static add(a, b) {...} 29 | static sub(a, b) {...} 30 | static mul(a, b) {...} 31 | static div(a, b) {...} 32 | static clamp(t, lowerLimit, upperLimit) {...} 33 | static min(a, b) {...} 34 | static max(a, b) {...} 35 | static minNum(a, b) {...} 36 | static maxNum(a, b) {...} 37 | static reciprocalApproximation(t) {...} 38 | static reciprocalSqrtApproximation(t) {...} 39 | static sqrt(t) {...} 40 | static swizzle(t, x, y, z, w) {...} 41 | static shuffle(a, b, x, y, z, w) {...} 42 | static and(a, b) {...} 43 | static or(a, b) {...} 44 | static xor(a, b) {...} 45 | static not(a) {...} 46 | 47 | //Boolean vector computational Factories (all return Int32x4) 48 | static lessThan(a, b) {...} 49 | static lessThanOrEqual(a, b) {...} 50 | static equal(a, b) {...} 51 | static notEqual(a, b) {...} 52 | static greaterThan(a, b) {...} 53 | static greaterThanOrEqual(a, b) {...} 54 | 55 | //selection Factories 56 | static select(laneSelector, trueValues, falseValues) {...} 57 | static bitSelect(bitSelectionMask, trueValues, falseValues) {...} 58 | 59 | //from TypedArray factories 60 | static load(array, index) {...} 61 | static load1(array, index) {...} 62 | static load2(array, index) {...} 63 | static load3(array, index) {...} 64 | 65 | //prototype methods 66 | get [Symbol.toStringTag]() {return "Float32x4"} 67 | } 68 | 69 | //-------------------------------------------------------------- 70 | //module SIMD -- with prototype methods for operations 71 | 72 | export class Float32x4 { 73 | constructor (v1, v2, v3, v4) { ...} 74 | 75 | //factory methods 76 | static splat(v) {return new this(v, v, v, v); 77 | static fromFloat64x2(t) {...} 78 | static fromInt32x4(t) {...} 79 | static fromFloat64x2Bits(t) {...} 80 | static fromInt32x4Bits(t) {...} 81 | static fromInt16x8Bits(t) {...} 82 | static fromInt8x16Bits(t) {...} 83 | 84 | //from TypedArray factories 85 | static load(array, index) {...} 86 | static load1(array, index) {...} 87 | static load2(array, index) {...} 88 | static load3(array, index) {...} 89 | 90 | //selection Factories 91 | static select(laneSelector, trueValues, falseValues) {...} 92 | static bitSelect(bitSelectionMask, trueValues, falseValues) {...} 93 | 94 | // predicates 95 | static isFloat32x4() {[[hasTag]](this, "Float32x4Tag") ? v : throw new TypeError} 96 | 97 | // accessor methods 98 | extractLane(i) {...} 99 | store(array, index) {...} 100 | store1(array, index) {...} 101 | store2(array, index) {...} 102 | store3(array, index) {...} 103 | 104 | //computational operations 105 | abs() {...} 106 | neg() {...} 107 | add(b) {...} 108 | sub(b) {...} 109 | mul(b) {...} 110 | div(b) {...} 111 | clamp(lowerLimit, upperLimit) {...} 112 | min(b) {...} 113 | max(b) {...} 114 | minNum(b) {...} 115 | maxNum(b) {...} 116 | reciprocalApproximation() {...} 117 | reciprocalSqrtApproximation() {...} 118 | sqrt() {...} 119 | swizzle(x, y, z, w) {...} 120 | shuffle(b, x, y, z, w) {...} 121 | and(b) {...} 122 | or(b) {...} 123 | xor(b) {...} 124 | not() {...} 125 | 126 | //Boolean comparisions (all return Int32x4) 127 | lessThan(b) {...} 128 | lessThanOrEqualb) {...} 129 | equal(b) {...} 130 | notEqual(b) {...} 131 | greaterThan(b) {...} 132 | greaterThanOrEqual(b) {...} 133 | 134 | //other methods 135 | get [Symbol.toStringTag]() {return "Float32x4"} 136 | } --------------------------------------------------------------------------------