Oliver Hunt wrote:
On Nov 18, 2012, at 6:17 PM, Matt Calhoun<[email protected]> wrote:
I believe that having a concise notation for linear algebra is an important feature of a programming language that can dramatically improve code readability, and furthermore that linear algebra is a powerful tool that has many applications in java script. I would like to make the following two suggestions:
1. Extend the "+" operator to work on Array's of numbers (or strings).
2. Allow for scalar multiplication of Array's which contain only numbers.
Although there are many problems with a simple linear algebraic solution which arise in contexts where java script is a natural language of choice (for example WebGL), there are no simple ways to express these solutions in java script because the language itself creates a barrier to even basic operations such as subtracting two vectors, in the sense that the amount of writing it takes to express these operations obscures their mathematical content. For more complicated linear algebraic work, the problem is quite severe.
Changing the behaviour of any of the basic operators on builtin/pre-existing types is essentially a non-starter. + already has sufficiently, errr, "sensible" behaviour to be widely used on arrays. Other operators don't really have any such "sensible" use cases, but changing their semantics on one kind of object vs. other kinds would be highly worrying.
(2) would also be a non-starter i feel: JS implicitly converts to number in all other cases, and if we made operator behaviour dependent on content type (in a nominally untyped language) I suspect we would very rapidly end up in a world of semantic pain, and another WAT presentation.
I think we could actually reduce the WAT effect in JS with *opt-in*
operators for value objects. This is on the Harmony agenda:
http://wiki.ecmascript.org/doku.php?id=strawman:value_objects
http://wiki.ecmascript.org/doku.php?id=strawman:value_proxies
I've implemented int64 and uint64 for SpiderMonkey, see
https://bugzilla.mozilla.org/show_bug.cgi?id=749786, where in the patch
there's a comment discussing how the operators for these new
value-object types work:
/*
* Value objects specified by
*
* http://wiki.ecmascript.org/doku.php?id=strawman:value_objects
*
* define a subset of frozen objects distinguished by the
JSCLASS_VALUE_OBJECT
* flag and given privileges by this prototype implementation.
*
* Value objects include int64 and uint64 instances and support the
expected
* arithmetic operators: | ^ & == < <= << >> >>> + - * / %, boolean
test, ~,
* unary - and unary +.
*
* != and ! are not overloadable to preserve identities including
*
* X ? A : B <=> !X ? B : A
* !(X && Y) <=> !X || !Y
* X != Y <=> !(X == Y)
*
* Similarly, > and >= are derived from < and <= as follows:
*
* A > B <=> B < A
* A >= B <=> B <= A
*
* We provide <= as well as < rather than derive A <= B from !(B < A)
in order
* to allow the <= overloading to match == semantics.
*
* The strict equality operators, === and !==, cannot be overloaded,
but they
* work on frozen-by-definition value objects via a structural
recursive strict
* equality test, rather than by testing same-reference. Same-reference
remains
* a fast-path optimization.
*
* Ecma TC39 has tended toward proposing double dispatch to implement
binary
* operators. However, double dispatch has notable drawbacks:
*
* - Left-first asymmetry.
* - Exhaustive type enumeration in operator method bodies.
* - Consequent loss of compositionality (complex and rational cannot be
* composed to make ratplex without modifying source code or wrapping
* instances in proxies).
*
* So we eschew double dispatch for binary operator overloading in
favor of a
* cacheable variation on multimethod dispatch that was first proposed
in 2009
* by Christian Plesner Hansen:
*
* https://mail.mozilla.org/pipermail/es-discuss/2009-June/009603.html
*
* Translating from that mail message:
*
* When executing the '+' operator in 'A + B' where A and B refer to value
* objects, do the following:
*
* 1. Get the value of property LOP_PLUS in A, call the result P
* 2. If P is not a list, throw a TypeError: no '+' operator
* 3. Get the value of property ROP_PLUS in B, call the result Q
* 4. If Q is not a list, throw a TypeError: no '+' operator
* 5. Intersect the lists P and Q, call the result R
* 6. If R is empty throw, a TypeError: no '+' operator
* 7. If R has more than one element, throw a TypeError: ambiguity
* 8. If R[0], call it F, is not a function, throw a TypeError
* 9. Evaluate F(A, B) and return the result
*
* Rather than use JS-observable identifiers to label operator
handedness as
* in Christian's proposal ('this+', '+this'), we use SpecialId
variants that
* cannot be named in-language or observed by proxies.
*
* To support operator overloading in-language, we need only provide an API
* similar to the one Christian proposed:
*
* function addPointAndNumber(a, b) {
* return new Point(a.x + b, a.y + b);
* }
*
* Function.defineOperator('+', addPointAndNumber, Point, Number);
*
* function addNumberAndPoint(a, b) {
* return new Point(a + b.x, a + b.y);
* }
*
* Function.defineOperator('+', addNumberAndPoint, Number, Point);
*
* function addPoints(a, b) {
* return new Point(a.x + b.x, a.y + b.y);
* }
*
* Function.defineOperator('+', addPoints, Point, Point);
*/
This is all experimental and not for ES6, but it does not increase the
WAT effects, quite the contrary. int64, uint64, decimal, bignum,
complex, and even vector and matrix value object types for linear
algebra and graphics applications need operators and literal syntax for
usability. Requiring method-based or functional APIs is just
user-hostile and drives developers back toward binary double. See
http://www.jroller.com/cpurdy/entry/the_seven_habits_of_highly1
especially the first comment.
Also anytime i've seen someone propose * operating on arrays it rapidly becomes a flamewar between element-by-element multiplication and n-dimensional-dot-product.
I agree that * or other operators should not be naively supported on
arrays, which are not value objects in any case. Any vector or matrix
value object would want sweet literal syntax, but it wouldn't be array
literal syntax, exactly.
The use-cases want opt-in operators/literals via modules, with a
principled approach to avoiding adding support for * to arbitrary other
code. Lexically scoped operators, perhaps as hygienic macros a la a
future sweetjs.org approach (infix operator macros are on the agenda
there, not yet supported), is the way to go.
Anyway, Matt's request is reasonable in my view, when phrased in terms
of well-scoped opt-in extensions rather than magic new-default behavior
for arrays.
/be
ES6 provides comprehensions however that might make the world nicer for a lot of your use cases.
--Oliver
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss