Support for basic linear algebra on Array's
Alex Russell
alex at dojotoolkit.org
Mon Nov 19 01:15:12 PST 2012
I like this as a rough solution. Assuming we get Array sub-typing done in a similar timeframe, it might all fold into a nice tidy package.
On Nov 19, 2012, at 3:08 AM, Brendan Eich <brendan at mozilla.com> wrote:
> Oliver Hunt wrote:
>> On Nov 18, 2012, at 6:17 PM, Matt Calhoun<calhoun137 at gmail.com> 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
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
--
Alex Russell
slightlyoff at google.com
slightlyoff at chromium.org
alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723
More information about the es-discuss
mailing list