-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Identifying the goal of the proposal #15
Comments
Is it possible to do both
|
I think it's the same goal. It's no sense to check not fully instantiated object. |
There is some sense in checking this: object construction can fail. So, if you want to verify an instance is correctly constructed, this proposal provides that mechanism -- after which the author may freeze the object to prevent any modification. It gives you guarantees that the object you are working with has not been tampered with and is complete. That said -- this doesn't have to be the goal of this proposal. this grew out of the discussion with how this proposal differs from ergonomic brand checks. It certainly has use cases but they are very specific. On the other hand, if we are overlapping in terms of the happy path (constructor does not throw), then the question about "what does an instance mean to developers" is a relevant question to answer. This might be, as @Jack-Works suggested, a mental model which also includes checking the prototype. This would be a good area to explore. |
@codehag It's not only "not throw". Actually throw is common. We use throw to express that the request of constructing a new object is not valid. The happy path we discussed should be:
The self-contradict part of the I will be VERY VERY VERY frustrate if now committee refuse this proposal by the reason "because the happy path we don't need |
This isn't what is happening here. I am seeking clarification, which may lead to changing the name in order to better communicate, or possibly adding behavior to address an issue you also brought up -- that "brand check" may not be strictly meaningful for developers. As I mentioned, for me personally the problem represented here is broader than class instances, and ideally we would look at how this might be done more broadly -- I also know this might be impossible or not your goal. This isn't a blocking concern and we don't need to spend time on it if it isn't of interest. Edit to add: please note that I explicitly did not block this proposal from advancing as a lone objector. this is all something that can be clarified in a more mature stage, but my preference is that we are on solid ground first. |
Sorry I may misunderstand the things due to language barrier (this is a long term issue for me and all chinese delegates).
I'm not sure I fully understand your concern. Do u want some more general brand check mechanism not only for classes? As I said, I don't think brand check is a familiar concept to average programmers. So this proposal is named as "brand check" just to match the TC39 jargon. And another problem is it's hard for me to imagine how we could have a much general "brand check" out of classes. It seems currently only classes need that. Builtins and platform apis also need brand but it's out of the scope of this proposal, I remember 2021 Jan meeting already have a topic for that. And it's possible that we could have tagged record/tuple or struct which have brands to differentiate the values of different kind of struct, but definitely it could use other syntax, or i guess very likely don't need special syntax.
I don't treat "impossible", I just not fully understand your (and some others) expectation on this area, so i even don't know whether it could be my goal. |
As a JavaScript developer who wrote and maintains a library (that is about the size of lodash), to me:
This is a like the Liskov Substitution Principle, but applied to instances in a dynamically-typed, prototype-based language. However, neither Based on my current understanding, the utility of brand check, for me, would be that the runtime could provide the desired guarantee for classes I author, or review, when the prototype and all constructed instances are frozen. Edit: the class constructor might also need to prevent extension by unknown sub-classes. I haven't tested, but I think this could be done by checking |
yes, this is a harder problem. I don't know how to solve it myself. But this is what I mean by more general. This is also one of the more difficult parts of javascript and the spec just because of how dynamic things are. I think this proposal can be justified in it's own right, but there are two independent reasons for this proposal to exist: 1) a descriptive api (better for reading and understanding), and 2) a way to guarantee the initialization of the class. These two distinct things are linked by the history of the proposal rather than by the intent. In my initial comments, I was focused on the first -- if we are adding this new ergonomics, how has the existing proposal been doing, what can we learn from that? We don't need to rush forward with proposals, we can take our time and fully understand the holes left behind by previous work. I won't press on this issue though. For the second one, I don't think many developers would realize that Correct me if I am wrong, I think you may be more interested in the ergonomic use case? So my question in this case is, is this a complete solution for this use case? Including situations like what shu described about changing the prototype chain? Traditionally, instanceof in JS has been checking for the constructor on the prototype chain. Thinking out loud here...:
Sorry for the million edits. I am likely misunderstanding something, as I quickly sketched this out with ergonomic brand checks. I thought i got it wrong, then it turns out i got it wrong in the wrong way. Here is the full polyfill version: var _set1 = new WeakSet();
var _set2 = new WeakSet();
var _set3 = new WeakSet();
class X {
constructor() {
_set1.add(this);
}
equals(range) {
return _set1.has(range);
}
}
class Z {
constructor() {
_set3.add(this);
}
equals(range) {
return _set3.has(range);
}
}
class Y extends Z {
constructor() {
super();
_set2.add(this);
}
equals(range) {
return _set2.has(range);
}
}
var yInst = new Y;
var xInst = new X;
var zInst = new Z;
console.log(yInst instanceof Z) // true
console.log(zInst.equals(yInst)) // true
console.log(yInst instanceof Y) // true
console.log(yInst.equals(yInst)) // true
console.log(yInst instanceof X) // false
console.log(xInst.equals(yInst)) // false
Object.setPrototypeOf(yInst, xInst);
console.log(yInst instanceof Z) // false
console.log(zInst.equals(yInst)) // true
console.log(yInst instanceof Y) // false
console.log(yInst.equals(yInst)) // false.
console.log(yInst instanceof X) // true
console.log(xInst.equals(yInst)) // false Ok, what would be the ideal situation here? I was thinking that one would be related to the prototype, and one related to how the object was initially constructed. Again, sorry for any confusion from me editing the post 100 times. |
If
Otherwise the following might become a generally recommended 'best practice' class C { static isC(o) { return o instanceof C && class.hasInstance(o) } } So, I think Jack Works' suggestion would need to be assumed. |
I don't think these two things is separated, at least for most people who use classes, follow the OOP concept, "fully instantiated" is the prerequisite of "an object is what it says it is". There may be the gap: I don't think people "check that an object is what it says it is" means they want to do "brand check". This proposal add class "brand check" as the mechanism of "check instance", but "brand check" is not the goal. We also don't want to expose "brand" concept to developers. What "brand" check is ? As I understand, a "brand" as TC39 term, means some code have the power to classify the objects into two category: those have the brand, those not have. And no other code can change or forge it. So it's a very general concept, most time too general. We already have the right tool for branding, that's weakset. I don't think we need any other feature to make branding much ergonomic in general way. Because 1. it seems just invent another way to do the same thing, 2. you can't make a "too general" thing really ergonomic, because there is no enough context. This is why I feel On the other side, the common usage of the private fields do not need per field check. So "check that an object is what it says" is really the task we should provide much ergonomic, intuitive way for programmers. And "check the object has fully instantiated by the class" is the part of the definition of "check that an object is what it says". It's doesn't make sense to say it's the object what it says but not fully instantiated or in a broken state. So I think that's why @XGHeaven said "it's the same goal." |
I think we are talking past each other. Lets take ergonomic brand checks out of the picture. It has been an unhelpful distraction to this proposal. You have mentioned that you do not actually care about the completed object -- thats also fine, and it answers my question. So we can ignore item 2. The problem, as I understand, that you want to solve is that instanceof doesn't really work. You mentioned (and I fully agree) that "brand check" doesnt mean much to developers. The question raised at plenary by shu was "what guarantees should this provide". Let's check our shared understanding of that, using the following code:
|
The way I’d describe it is: zInst has all the slots/fields/constructor behavior of Z and Y, and has all the methods of Z, Y, and X - so it’s a “true instance” of Z and Y (because it meets both sets of criteria) and it inherits from X (which may, or may not, allow it to “work like an X”, depending on X’s internal implementation details). Knowing the former means i can borrow methods (.call, etc) and expect them to work reliably; knowing both means i can directly call methods reliably (assuming method also haven’t been replaced, which is a separate issue); knowing only the latter requires me to make assumptions or know implementation details. |
To quickly clarify, In this case (sorry it isn't well written), Y inherits from Z, not Z inheriting from Y. So Z does not have access to Y's slots. The prototype has been moved for yInst from Y & Z, to xInst (X). You can see a full runnable example of this here |
Right; but it means Y’s methods can access Y’s fields, and Z’s methods Z’s; I’m assuming each class’ methods are written to use their own fields. |
Interestingly we have the following for yInst in this case:
Right, so -- this was what i was thinking of when i thought "it is interesting to be able to verify what this was constructed with, not what it might be now. I wonder if this translates to an OOP model as hax is citing, in a language that is prototypical, to something that should be called an "instance" -- especially since it is giving a fundamentally different answer than ... isConstructorOf also references prototype.constructor, but in some ways that is the underlying ambiguity clarified by this. This would be a complementary relationship. |
|
yep, i think that would also work. I do think that this is a valuable piece of information to have and would warrant this proposal. This issue would be resolved as a naming bikeshed in that case. But i also respect what hax has been saying here, and the group that he has been working with is not interested in this property by itself -- rather they are interested in a concept of an OOP "instance", which is different how javascript has been treating it in the prototypical paradigm. This is not well represented by this |
I see two distinct goals of this proposal:
for 1, I would like to better understand how ergonomic brand checks are doing right now. The happy path for both of these results in the same -- a check if an object is what it says it is. So how is that doing? what are people using it for? Is it primarily library authors? polyfill authors? who did we reach?
As mentioned in your presentation, maybe a "brand check" isn't something developers are actually interested in. Maybe they have a more abstract concept -- something like "instanceof" -- but instanceof is broken in javascript.
As I mentioned, this is a problem that impacts the language more broadly. I'd love to see a broad solution, but maybe we can do something just for classes to solve a subset of that problem.
for 2) we might be able to reuse this for this guarentee, but if this is the primary goal, I would expect a different name. Something like class.initiatedAs(o) or class.isInitiated(o).
The text was updated successfully, but these errors were encountered: