Questions about `writeable` with extended classes

class Base {
  method() {}
}

Object.defineProperty(Base.prototype, 'method', {
  value: Base.prototype.method,
  writable: false,
});

class SafeExtended extends Base {
  // this works fine
  method() {}
}

class Extended extends Base {}

// TypeError: Cannot assign to read only property 'method' of object '#<Extended>'
Extended.prototype.method = function method() {};

I'm wondering: which part of the spec dictates this behavior?

Oh great. Firefox and Chrome run the test code, but Node throws the error.

Nope, actually this code errors in strict mode it turns out, but not in non-strict mode

This is the so-called “override mistake”. The fact that properties fail to assign when there is an existing non-writable is a consequence of OrdinarySetWithOwnDescriptor step 2.a; the fact that this also applies when such a property exists on the prototype is because of OrdinarySetWithOwnDescriptor step 1. This throws in strict mode because of PutValue step 3.e. Generally if you’re wondering “what part of the spec dictates this behavior” you can start at the evaluation semantics for the relevant line and trace through from there.

As you can infer from the fact that this is referred to as a “mistake” it is generally not liked, but it has not thus far proven web-compatible to change; doing so would affect a lot of code.

1 Like

Good to know. I had been using classes to define parser grammars that looked like this:

class JsonParser {
  Null(p) { p.eat('null' },

  Boolean(p) { /* ... */ }
}

It was relatively obvious why I wanted both things: once you define the JSON grammar, you don't want it changing, but you do want to be able to create a different language extended from JSON. Plus it's nice to have decorator support.

I sort of can still do that, but I was also depending on being able to do a mapProductions operation on the class, and that's what I no longer know if I will be able to do.

Honestly I'm on the fence at this point about whether to consider forking the whole language at some point in the future.

My general feeling about TC39 is that it's a lame duck council now. It isn't proactive. It doesn't communicate. It aggressively cuts scope from everything so that each new features integrate with only 2/3 of the other features in the language. Only a very few people involved care to interact with the community here.

It seems to me now that TC39's hold on power is extremely tenuous. Microsoft has stripped away a massive portion of the comittee's agency by being in control of the dialect that engineers write on a daily basis.

Aside from saying "we're in charge" the main instrument of TC39's authority is Babel, but Babel is also not likely to be authoritative for much longer (between Rust rewrites and BABLR).

And in the middle of all that me: the most active contributor to the next generation of the language and its tools by a mile, and I still feel like a pariah in this community precisely because I'm trying to develop a coherent vision and am considering breaking changes to make it happen.

You can use Object.defineProperty for this scenario. It’s annoying, but it does work.

1 Like

...it does work!!

Thank you, thank you, that's enough to get me moving forward again on what I was trying to get done : )