tc39/proposal-private-fields-in-in

No need to support strong class inheritance checks here

aimingoo opened this issue · 3 comments

JS class inheritance is based on prototype inheritance. There is no way to guarantee that an object-o created from class-C has the features of the parent class. and vice versa, there is no guarantee that any object-o2 does not have the featuresof class-C. So why add a strong and official type checking method to class declaration?

Try next case:

class C {
  #x
  isC(o) {
    return true; // or other way: `#x in o`
  }
  aMethod() {
    // do somethig
  }
}

x = new C;
Object.setPrototypeOf(x, null)
x.isC = C.prototype.isC;

// I try a hard class brand check, say `yes`
x.isC(x); // true

// crash!
x.aMethod(); //  x is duck-type instance.

So, Does strong/hard class brank check have any meaning?

I'm afraid you are a bit mistaken. JS is full of these kinds of checks - every single builtin (except Error) has methods that check for the presence of "internal slots" and throw when they are missing, and user code that extends these builtins can participate in this branching. User code can already ensure this with use of private fields, or with a Weak collection in a closure. Thus, there already is, and has been since JS's inception, the ability to guarantee that an object passed through the appropriate constructor code. This proposal is merely about a more ergonomic way to perform these pre-existing checks.

In your example, you're looking up aMethod on x, after the [[Prototype]] has been modified, so certainly you're not getting the method you expect. However, if you do C.prototype.aMethod.call(x) (as code that cares about being robust often does, which admittedly is not a common practice overall), then it will continue to work as expected. Additionally, if a static method is doing the slot/field lookup, then this issue wouldn't occur.

The type dependency, or type detection dependency is undesirable. For example, how to determine that a function is a constructor and use new operation further?

// How to ensure that f() is always safe?
if (IsConstructor(f)) then
  new f
fi

so, I support annotations/decorators and static syntax checking. It is a credible method and always puts security in the hands of the developers of the application or library.

I greatly desire runtime detection, and prefer not to rely on build-time detections. Let’s not debate the credibility of type systems or static checking here, as these are irrelevant to the JS spec.

you’re right that there’s no convenient IsConstructor check (you’d have to check it with Proxy, and even then a constructor could still throw) but that doesn’t lessen the value of the majority of things that are robustly checkable at runtime.

Thanks for your feedback!