March 22/23 notes

Waldemar Horwat waldemar at google.com
Wed Mar 23 17:10:45 PDT 2011


Here are my raw notes from the last couple days.

Ask the GA for a way for non-members to sign software contribution agreements?
Waldemar:  Thinks this would be a hard sell in the GA.  They'll be
annoyed at increasing provisions for non-members to participate.
Istvan:  This should not be "too innovative", at least until we get a
lot more experience.  ECMA should not directly accept third-party
contributions.  An ECMA member should serve as an intermediary.
Allen:  This is already coming up in the context of Test262.  Third
parties are coming up with tests and we would like those tests.
John:  Are the third parties willing to assign the code to one of the
ECMA members?

Binary data:
Typed arrays != ArrayTypes.  DaveH is proposing ArrayTypes but not ArrayTypes.
In practice there is little difference between them.  ArrayType(int16)
is drop-in replacement for Int16Array.
DaveH is proposing ArrayBuffers (not currently on wiki).
Every instance of an ArrayType or StructType (instance that contains
actual data, not the type object itself) is also an ArrayBufferView.

Discussion of whether the raw buffer should be exposed for ArrayTypes
created for in-program (non-i/o) use only.  With this view, any client
can extract the buffer and must get a specified view (big endian by
default).
Allen:  Ability to extract the buffer from "new new ArrayType(int32,
100)" forces implementations to store it as big-endian even if they
would rather not.  This impedes performance.

Slide with:
MyType MyType(ArrayBuffer buff, uint32 idx = 0, uint32 length =
buff.byteLength - idx, boolean networkByteOrder = true);
Waldemar's misinterpretation of the bool:  networkByteOrder = true
means big endian.  networkByteOrder = false means localByteOrder,
which can be big or little endian, depending on local hardware.  To
avoid such interpretations, if this bool is meant to distinguish
between big and little endian, call it bigEndian.

Brendan: What if we don't allow aliasing of multiple-sized
interpretations for the same data?  i.e., once something is an int32,
can't access it as int16 or bytes?
Waldemar: This would break the common case of creating structures that
contain crc's or digital signatures of parts of their content.
MarkM: Any reason to allow a fuzzy (rather than explicitly specified)
byte order for such cases?
Waldemar: No.

Waldemar: What's the practical user-visible difference between
ArrayBuffers and Blobs?

Alignment: Atomic types within a struct must be naturally aligned.
Struct lengths must be naturally aligned to the largest data member.

What about unaligned use cases?  These are fairly common in file
formats.  Most processors have some way to access unaligned types
which is substantially faster than extracting single bytes in
ECMAScript and shifting, so we'd want to allow it in some form.

DaveH: Solution:  Packed types vs. unpacked types.

Luke: Fall back to data views if structs don't solve a problem well.

Waldemar: Most files contain lots of string data in various formats
(UTF-8, UTF-16, ASCII, etc.).  The complete lack of string support is
the major obstacle to using this framework to parse files.  User
programs will have to parse UTF-8 and construct strings byte-by-byte
(which might be O(n^2) on some implementations if accumulating a
string by concatenation.)

Consensus on moving what's currently on the wiki page into harmony,
with ArrayBuffers and strings as important goals for additions.

Doug: Concerned that we started with just moving data to GPUs but are
now expanding scope into the much larger issues of file i/o.
Allen: Why not make a separate task group to standardize just this?


Module loaders:
Waldemar: evalLoad:  Is it always asynchronous?  Yes, but should
discuss this on a different thread.
Example:
l.load("my-module-url", myCallback);  // The module at my-module-url
references global g
l.defineGlobal("g", 42);
Note that mere compilation of my-module must not begin until after the
main thread completes; otherwise it wouldn't see the global "g".

l.defineGlobal("f", function() {...});
has the same behavior as:
var f = «function»;
except that «function» is created in the global context of the caller
of defineGlobal, not l's global context.  «function» is then bound as
l's global variable "f".

Waldemar, Brendan: resolver.resolve/load/eval don't work well with
redirects.  You want to use the target of the redirect as the cache
key, but by then you're in load and it's too late to do the resolve
cache lookup.  Origin policies also use the target of the redirect.

Custom loaders: when base.Array is not the usual Array object, what
happens when evaluating an expression like []?
DaveH: Core of the object is the standard Array, but the mutant Array
constructor gets to run too.
Waldemar: What exactly does that mean?
Allen: Emphasis on constructors is misplaced.  Other contexts are also
important.
Waldemar: Agree.  Suppose you swap Array with RegExp.  RegExp methods
refer to hidden magic properties that are not on standard objects.
They work and stay hidden because construction is coordinated behind
the scenes with the other methods.
MarkM: Make base optional in loader.create.


Move Modules to proposal status?
Doug: Modules are one of the most important features, but too early to
move it to proposal.
Debate over what "proposal" means.
Doug withdraws objection.

Quasis Q&A:
Q. Do we have plans to standardize functions like safehtml?
A. No, we will not standardize the functions.
Q. How does safehtml decide when quoting a message like "<b>bold</b>
word" into HTML whether to keep safe tags such as <b> or whether to
escape them into <b>?  There are plenty of use cases for both
situations and neither dominates.
A. Plain strings are assumed to be raw text. To avoid escaping things
like HTML you need to pass in a parameter of a special type other than
string.
Debate about whether quasis are a lexical or syntactic grammar
production.  They're lexical and deliberately don't include an
expression subgrammar for SubstitutionBody.  The text is lexed via
SubstitutionBody and later parsed.
Concern about grammar complexity of substitutions, particularly with nested `'s.
Brendan: Why currying and thunking and assignable substitutions and
all this complexity?
None of the use cases (other than Decomposition Patterns, which also
use setters) require thunks.
Brendan: By default simply interpolate the components if no function
is specified.
Lively debate on the default.  Doug: This will bring back security
holes.  DaveH: Simple concatenation useful for logging.
DaveH: It would be good to have an HTML sanitizer in ECMAScript, just
like how we have encodeURI, regardless of who standardizes it.
Waldemar: Often want to refer to properties of a late-bound object,
not the local variables.  See internationalization example below.

Concern about lack of ability to indirect, as needed by, for example,
internationalization.  How do you obtain messages from a library and
pass them indirectly into code?  Each message captures variables at
the point where it syntactically lies in the program, but here we want
to late-bind the parameters.

To do this, you'd need to write tables of:
English:
function hellomsg(o) {
  return msg`Hello, ${o.world}`;
}
function basemsg(o) {
  return msg'All your ${o.base} are belong to us";
}

French:
function hellomsg(o) {
  return msg`Bonjour, ${o.world}`;
}
etc.

Status?  Brendan:  "Sounds like this needs another run through the body shop."


Infix operators:
??  Replace undefined with a different value
Do we want to also change the default parameter syntax to use ??= instead of = ?
Metadiscussion about complexity budget.

has
mod
div
min
max

Syntax is compatible with ES5 (as long as there is a [no linebreak
here] before the keyword) but precludes some considered extensions
such as attributes decorating definitions.
Debate about reverse direction of "has" vs. "in".
Brendan:  Not clear if "has" is worth it.
"mod" produces the same sign as the divisor (as opposed to %, which
produces the same sign as the dividend).
How is "div" different from a division followed by truncation towards
zero?  They're almost the same, but the intermediate division can
round up to the next integer if it's within 1/2 ulp of an integer,
while div wouldn't.
Brendan:  Sympathetic to "mod" and "div" because the versions that
people should use are obscure or wordy.
Why not ** for power?
"min" and "max" feel weird as infix operators.

Number.prototype.compare(v, t): |n - v| < t?
Waldemar: This is the wrong comparison in many cases.  Often you want
to do a relative one.  There is no single such comparison that would
work in a majority of cases.

Number.EPSILON: nextdouble(1.0) - 1.0
Number.MAX_INTEGER: 2^53 exactly.  It's the largest double d such that
d - (d - 1) = 1.
Complaints about the name MAX_INTEGER.  It's not the maximum
representable integer; in fact, every finite double greater than
MAX_INTEGER is also an integer.

Various math functions on spreadsheet:
Some are commonly used (hyperbolics, exp2, erf, erfc, gamma).
Some are useful to avoid cancellation (e^x - 1 near x = 0).
Some are useful fp format manipulations (nextafter, split into
sign/mantissa/exponent and back).
Most of the rest are esoteric.


Object initializers:
Is the thing created by [<proto: myProto>, "a", 2, false] an Array (by
isArray) or not?  Yes.
Syntax collision with E4X.
Brendan: Don't like comma after >.  Too easy to miscount number of elements.
Waldemar: Like comma after >.  Without comma, the above example would
look like a greater-than expression myProto > "a".
Method declarations within object literals:
Are those allowed in arrays?  No.  You can't make an array literal
with its own toString method.

Object literal property modifiers:
p: value
p const: value
var p: value
var p const: value
sealed p: value
sealed p const: value
sealed var p: value
sealed var p const: value
method p() {}
sealed method p() {}
set p(v) {}
var get p() {}
sealed put p(v) {}
sealed var get p() {}

Waldemar: Why is "var" a prefix but "const" a suffix?  Too confusing.
The property name p should be in a consistent place (preferably last
because that's existing usage for getters).
Brendan: "var" and "const" in the same property declaration? "var"
does not intuitively mean "dontEnum".
Brendan: configurable=true, writable=false combination not necessary?
Waldemar: Since any keyword is usable as a property name here, what
does this do?
var const:value
Is it defining property "var" with attribute const, or property
"const" with attribute var?
What if someone makes a typo and forgets the property name?  Many of
the above forms will declare a property named "var", "const", etc.

Private names in initializers: Controversy about 'private' capture
semantics, orthogonal to object initializer syntax.

class c {
  method m() {return this.a+this.x} [HERE]
  new (a) {
    a: a,
    {this.x = somebody(this)}
  }
};
Controversy about what punctuation goes into the place marked [HERE].
If classes are based on object initializer syntax, there has to be a
comma there.  Brendan: users won't expect that.

class D {
  <superclass: C, frozen>,
  new (a) {
    <closed>,
    a: a,
    {this.x = somebody(this)}
  }
};
Note that the closed property is applied after the initializer block is run.

Debate about class private vs. instance private vs. ergonomics of
protection by scoping.
Allen:  Private must satisfy:
- Can't reflect on it
- Proxies can't trap them
- Don't need to stick lots of closures into each instance of a class
just to close over private members.
Dave:  Some of these can be relaxed.

Discussion about how the private mechanisms here subsume some of the
internal browser ones used to implement the DOM.

Initializers can dynamically created @-variables simply by assigning to them.

Waldemar: This is a problem:

class D {
  private iv1;
  ...
  new(a) {
    method m(v) {@iv1 = v;}
  }
}
my_d = new D;

class Evil {
  new(a) {{my_d.m.call(this, 33);}}
}
Evil gets to create @iv1 properties on its own objects without D's knowledge.

Allen: To fix this problem, disallow dynamic creation of @-properties
from constructor initializers.

Discussion about preventing methods from working on fake instances.

Dave:
var kye = Name.create();
function Thing(amIBlue) {
  this[key] = amIBlue;
}
Thing.prototype = {
  meth: function() {
    return this[key] ? "blue thing" : "red thing"
  }
}

var evil = Proxy.create({... get: #(key) {...} ...});
thing.meth.call(evil);

Dave: Every time a private name gets passed to a proxy, the name gets
wrapped.  (to what?)

private dance;
Thing.prototype.dance = fun() {...}

{
  private α;

  function Complex(r, i, α) {
    this.real = r;
    this.imag = i;
    this.α = α;
  }

  function setα(α) {
    this.α = α;
  }

  Complex.prototype.equals = fun(other) {
    return this.real == other.real && this.imag == other.imag &&
thia.α == other.α;
  }
}

Now you can again create fake Complex objects by creating an object
with real and imag properties and introduce an α property with setα.
This can fool the Complex equals method.

Debate about branding.

Brendan:  Should instance variables be non-properties (i.e. not
inherited from protype even if they don't use private names)?  Long
debate of cognitive load costs and other attributes pro and con.

Date example:  Users inherit from Date, but that breaks because Date
objects contain a hidden time field, which inherited ones don't.  If
that field were a private name, this would work.
But how would it work?  A possible scenario would be that all
BrendanDate objects (derived from Date) share the same hidden time
field, in which case changing one would affect the others.
To fix this, BrendanDate objects should call own-property methods, but
then there's no inheritance.  How would initialization of the hidden
field work?

Allen/DaveH:  Private names proposal on wiki will be modified to
support strong encapsulation.  Split proposal into runtime semantics
and syntax/scoping halves.

Open-ended discussion of many aspects of this proposal.  Not sure how
to summarize it.  It's also unfortunate that Mark isn't able to
present his proposal due to an emergency.


More information about the es-discuss mailing list