Oct 1 meeting notes

Brendan Eich brendan at mozilla.com
Fri Oct 1 18:49:31 PDT 2010

On Oct 1, 2010, at 4:38 PM, Waldemar Horwat wrote:

> Here are my raw notes from our second day.

Thanks again for taking these. Best tc39 note taker. ever. still.

> Unique names
> Question:  In what ways does this differ from weak tables?
> - A client can look up a property p using a[p] without knowing whether
> p is a traditional string or a unique name.
> Debate about private names leaking via proxies.  It's trivial to get
> at private names by passing a proxy to code that accesses them.
> It's not clear what private names are trying to do well.  If they want
> to provide privacy, they can't be visible to proxies.  If they want to
> provide extension without collision (i.e. namespacing), they should be
> visible to Object.keys, enumeration, etc.
> Allen:  private syntax is the primary usage of this proposal.  Debate
> over whether there should be two independent concepts of scope or one
> with a flag.

I think Allen's position is more on the "unique name" rather than truly "private name" side of the trade-off. FWIW.

> Brendan: list of questions:
> 1. Private for sure?
>  No: unique name weak encapsulation
>  Yes: Private name strong encapsulation

Perhaps we want both "unique n;" and "private n;".

> 2. Visible via for-in?
>  Object.defineProperty
>  Assignment via private

This bit included "either/or/both" with a dashed line, unlike the solid line between the "No: ..." and "Yes: ..." alternatives to 1, above.

> 3. Visible via Object.keys/getOwnPropertyNames?

The answer here depends not on 2 but on 1: if private names are truly private, then they don't leak via Object.keys/getOwnPropertyNames; else they do, and no worries ("weak encapsulation", par for the JS course).

> MarkM: Desugar
>  private n;
>  x.n = ...
>  x.n()
> into:
>  const n = SoftField();
>  n.set(x, ...);
>  n.get(x).call(x);
> Analogously, desugar
>  unique n;
>  x.n = ...  // Maybe make it nonenumerable by default?
>  x.n()
> into:
>  const n = Name();
>  x[n] = ...
>  x[n]()
> It's useful to view soft-fields as a kind of property names, but then
> have to address what happens on preventExtensions, freeze, etc.  If
> you think of these private fields as properties then they should be
> subject to freezing and such.

If you don't think of these soft fields as private fields *on the object* (so subject to preventExtensions etc.), then only inherited soft fields (not private name objects) can handle this novel use-case.

> A proxy having the right to get at an object's private field names is
> equivalent to a proxy having the right to obtain all weak maps for
> which the object is the key.  The security implications are the same.
> If a proxy can do a faithful membrane without one of these rights, it
> can do a faithful membrane without the other of these rights.  If a
> proxy has no rights to get at an object's private field names, the
> membrane will still work as follows:
> proxy[name] does not trap
> object[proxy] calls a trap on the proxy

Good point -- need a new trap here? Or is this get with an object-type property name?


> When a name object itself (not merely an object merely containing
> privately named fields) is passed through a membrane, the membrane
> wraps the name in a proxy p and then uses object[p] traps to maintain
> the membrane.  Private names would be used completely on either the
> wet or dry side of the membrane, so they'd stay private.  Public names
> that cross the membrane get proxied by the membrane.
> Binary data
> Given
> const Point2D = new StructType({ x: uint32, y: uint32 });
> const Color = new StructType({ r: uint8, g: uint8, b: uint8 });
> const Pixel = new StructType({ point: Point2D, color: Color });
> p = new Pixel({point: {x: 3, y:8}, color:{r: 100, g: 50, b: 0}});
> p.point.y returns the primitive integer 8
> p.point returns an alias (lvalue) to the Point2D substructure (block)
> of p.  Modifying data visible via such aliasing is visible to all
> aliases.
> Debate over whether values such as 3.8 or -1 should be assignable to a
> uint32 field.  Current proposal says no and provices a uint32(x)
> coercer method: uint32(-1) = 0xFFFFFFFF.
> Does calling p.point twice return block references that are === to
> each other?  Dave says he's agnostic.  Produced a bit of debate.
> Special updateRef feature to avoid creating lots of block wrapper
> objects (the blocks themselves are aliased so are less of an issue):
> var T = new StructType(...);
> var A = new ArrayType(T, 1000000);
> t = T.ref();  // allocate a homeless struct object
> for (i = 0; i < 1000000; i++) {
>  t.updateRef(a, i);  // no allocation of struct wrapper
> }
> Given this feature, it's no longer possible to be agnostic on ===.
> One can't make block references a === b if and only if a and b are
> aliases of the same block.
> One way out would be to have T.ref() return a separate updatable block
> type, while p.point or a[3] would produce nonupdatable block type
> objects.  Nonupdatable block type objects would have the above natural
> definition of === and not support updateRef.
> The counterpoint to the above is the creation of two kinds of block
> types, similar to each other.
> Debated desire for having blocks inherit from Array.prototype.
> Debated desire for having some Array generic methods on blocks.
> Endianness is invisible to users except when using blocks for file
> i/o, in which case the routines doing the i/o will take a parameter
> specifying the endianness of the file and convert as needed.
> How does one represent variable-length strings?
> Why no character types for fixed-size arrays?  Punted from proposal
> for time reasons for now, but are desirable.
> When using this for file i/o, handling of variable-length strings will
> become important.  How to do this?  No specific design, but some ideas
> are:
> Given struct {x: uint32, y: uint32, z: uint32, name: String}, an idea would be:
> string = new Layout({
>  length: uint16,
>  contents: function(me) {return new ArrayType(uint8, me.length)}
> });
> color = new Layout({
>  x: uint32,
>  y: uint32,
>  z: uint32,
>  name: string
> })
> How to store these in memory?  One can't have a pointer to a string
> inside a block.
> int64's:  Open issue.  Reference semantics are annoying, but what's a
> realistic alternative?
> int128's?  Those come up increasingly often in SSE programming.
> Waldemar:  Reify uint64's as 4-char big endian strings and uint128's
> as 8-char big endian strings.  A significant advantage is that these
> would have value semantics, and ==, ===, <, <=, etc. would all work
> correctly.  Would need to call methods to do arithmetic or signed
> inequality comparisons on them.
> More debate about block ===.  Reached consensus that two
> (nonupdatable) block references a and b should be === if and only if
> they are the same type and alias to the same data.  Updatable block
> references will have separate rules.
> Discussion on the use of put vs. defineOwnProperty in the ES5 spec as
> they relate to proxies and library classes.  Efficiency concerns with
> creating descriptors for defineOwnProperty.  Most array classes turn
> out to use put for objects which can be proxied; the places where they
> use defineOwnProperties tend not to be proxyable because they're done
> on locally created Array objects.
> Can a proxied [[construct]] return a primitive?  Yes.
> Brendan: How do we do feature detection and top-level patching in ES-harmony?
> if (!window.fooQuery)
>  var fooQuery = ....
> let clarifications:
> let x and var x at same scope:  error
> let x at top scope of a function or catch block with parameter x:  error
> let x at script top leve:  ok
> module M {
>  export let x;
> }
> var binding that would hoist across a let binding:  error
> let has a read barrier before the let statement gets executed:
> {
>  let x = 1;
>  if (x) {
>    alert(x);  // Read barrier error here because inner x hasn't been
> initialized yet
>    let x = 2;
>  }
> }
> {
>  x = 42;  // Write barrier error because x hasn't been initialized yet
>  print(x);
>  let x = 99;
> }
> Questions about whether
>  let x;
> should be treated as:
>  let x = undefined;
> so it has a barrier too.  Could take either position on this one.
> Brendan: What if let and const don't hoist at all (as in C++ scoping)?
> This was Waldemar's position before the grand ES4 scoping compromise
> a few years ago.
> Mutually recursive example (wouldn't work with const without some extension):
> let f, g;
> f = function() {... g ...};
> g = function() {... f ...};
> Another alternative for mutual recursion:
> let [f, g] = [function() {... g ...}, function() {... f ...}];
> This assumes that f and g are visible in the initializer, which would
> bring the barrier issues back.  Read barrier would be needed.  Debate
> about whether write barrier would be needed, even if we have
> expressions for typed/guarded let.
> Discussion of pragma syntax:
> use bignums;
> use harmony;
> use modules {A, B, C};
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

More information about the es-discuss mailing list