-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Something about Invariants in specification (needs clarification). #1628
Comments
For all objects except proxy exotic objects (or I guess host exotic objects, not sure what the correct term is for that), the invariants require no ‘enforcement’ because they ‘fall out’ of the algorithms themselves. For proxy exotic objects, where ES code may implement the meat of the object internal methods, the proxy objects’s actual object internal methods are like wrappers around the user code, and those wrappers have to explicitly perform checks to ensure that the should-be invariants are met, since the user code may have attempted violating them.
V is not an argument to [[Get]]. This variable is being defined in the invariant statement itself (a previous return value of [[Get]] when the stated criteria were met). When it says ‘with value V’ that means ‘with a specific value we will refer to as V’. |
just to clarify: if we take proxy's It calls the proxy's
|
The "essential invariants of objects" are stated in the spec because they are requirements imposed upon all objects, whether defined by a the specification, by an "engine" as extensions to the specification, by an host environment, or by user code. The specification takes care of ensuring that the specified built-in objects all conform and that user defined exotic objects implemented via Proxy also conform. But future spec writers defining new kinds of objects, engine implementors, and host implementors must ensure that any exotic objects they define conform to the invariants. Similarly any new mechanisms that allow user code to define exotic objects must ensure that the user defined objects conform to the invariants, just like Proxy does. |
@devsnek Something tells me that you're talking to me a little about something else. There is [[Get]] for ordinary objects, and there is for proxy [[Get]]. In your example, the line [[Get]] from the proxy. And I asked a question about [[Get]] for ordinary objects. Yes, in the proxy [[Get]] has a line that you described, but not in ordinary.
for ordinary objects. And there was not a word about this sentence:
|
In your original post, you only used the word "ordinary" once, when paraphrasing 6.1.7.3.
Ah, well, you didn't make that clear before. For an ordinary object,
@bathos and @devsnek both addressed this sentence. You should probably re-read their answers and then ask something more specific if necessary. |
I may have done a poor job of communicating what (I think) this means, so here’s another go: Certain facets of object behavior (including behavior over time) are epiphenomena that emerge from the sum of smaller details that may span multiple algorithms. They aren’t always obvious. The invariant statements make these behavioral properties explicit and say ‘this effect is intentional, and it is required that it be maintained even by exotic objects with custom internal methods’. In the example about [[Get]], it’s saying that once a property has been reported as an unwritable and unconfigurable data property once, the value returned by [[Get]] must never change again. If this weren’t established as an invariant, a property being unconfigurable and unwritable would cease to reliably have any meaning. Because a Proxy handler function could report any value at any time, the internal methods for Proxy exotic objects include steps that exist just to ensure the invariants don’t get violated. If the result of a proxy handler function (trap) would violate an invariant, these algorithms throw a TypeError instead, thereby maintaining the invariant. That’s what ‘runtime checks’ refers to. Other internal methods don’t need these same checks because they are already defined in such a way that provably will not violate the invariants. |
@jmdyck, actually by the context one could understand what I meant. You say that for ordinary objects [[Get]] is implemented via OrdinaryGet. And step 4 returns the value of the object.
In general, I would just like to see how an invariant will be executed for a normal and proxy object, with valid js code, this would be the best explanation. What @bathos and @devsnek answered is implicit to me. Since they do not specify specifically, referring to the proposal I have indicated:
Is it possible to explicitly indicate what will be: |
I’m confused about the final question, but regarding ‘execution’ of invariants — they aren’t executed. The invariants are just true statements about object behavior. Proxy objects have a unique need to perform runtime checks that correspond to these invariants because user code (via the handlers) might not do the right thing. Everything else is known to ‘play by the rules’ in advance; the invariants are satisfied by definition. For example, imagine a rule that an internal method [[Increment]] must always return an integer, and the integer returned must always either be greater than the previous value that was returned by [[Increment]] or must be the max safe integer. For ordinary objects, [[Increment]] might be defined to add 1 to a stored value and return the result. This algorithm is known to satisfy the invariant. No runtime check needs to be made. Now imagine a Proxy trap for this internal method. The trap function is user code, and we could define it as |
I gave an example of what I meant, in the text following the sentence you just quoted. If you want clarification, you'll have to say what part is unclear.
They aren't executed, they are either satisfied or not. If you like, you can imagine an auditor examining the result of every invocation of every internal method of every object. If those results ever fail to satisfy the invariants, then it's not a conforming implementation.
In @devsnek's example, the "trap" is the handler object's "get" method, which is obtained and bound to the
No, you don't "perform" invariants. Rather, step 10 performs runtime checks on |
@bathos sorry, I meant enforce instead perform. That is, for ordinary objects, invariants show their standard behavior in algorithms (but what's the point?) As for the proxy, it is clear that the user can create his own functions to override the behavior of internal methods. You gave an example with the abstract [[Increment]]. An invariant of which is such a statement for ordinary objects: Next you talk about the proxy. As I understand the invariant remains the same as in the case of ordinary objects. The first time is satisfied because max safe integer? (It is still not clear what is meant by this). The second time is not satisfied because the number is not changed? If we are talking about the difference of algorithms for ordinary and proxy objects, then I understand. |
Sorry, qualifying the toy example w/ ‘or max safe integer’ probably just added unhelpful noise; I was just hedging against a potential point of confusion about what I intended to communicate. It is probably better if that part is ignored.
Yes. The first time it’s okay (in this imaginary example) because there’s no prior number result, the second time it is not okay because the new number is not larger than the previous number.
Yes — I think so, anyway. There may be a terminology disconnect here, but it sounds like you have the gist. The proxy object’s internal methods don’t ‘trust’ the result of the trap, they have to take extra care to make sure the result conforms to the rules that other objects exhibit. |
@bathos That is, it turns out a double check for matching invariants when it comes to a proxy object. The first check is the check of the so-called “trap”, which is checked by invariants for ordinary objects, the second check is the check of the object proxy itself on its proxy invariants. @jmdyck Ok, then I am interested in the following:
|
There aren't "invariants for ordinary objects" and "proxy invariants". There are only invariants for all objects.
Yes, for proxies. Proxy objects are exotic objects. Once you've said "ordinary and exotic objects", that's all objects. The invariants specified in 6.1.7.3 Invariants of the Essential Internal Methods are invariants that all objects must satisfy. You should maybe re-read @allenwb's response above.
I don't understand what you're asking there.
I think so. You're puzzled that Here's a silly analogy. Imagine a bucket with two "internal methods", [[Put]] which puts something in the bucket, and [[Take]] which returns something from the bucket. And imagine there's an invariant on [[Take]] that says the thing returned must be red. One way to accomplish this is for the [[Take]] method to go through the things in the bucket until it finds a red one, and return that. But a different way is for the [[Put]] method to discard anything that isn't red, so the only things that go in bucket are red. Then [[Take]] just needs to reach in "without looking" and return anything in the bucket, safe in the knowledge that it will be red. So, with the second approach, even though the invariant is about the thing returned by the [[Take]] method, the [[Take]] method doesn't do anything to ensure that it's satisfied. In general, all of an object's internal methods work together to ensure that all of the invariants are satisfied. |
@jmdyck I just made a split, especially with other rules for proxy objects.
If we compare the first line in 1 and 2, then we note that this is the same thing. Or not? If not the same thing, then it is necessary to make a more obvious difference of what is meant. I read the answer @allenwb, it says that "essential invariants of objects" apply to all objects no matter how and where they are created. Although it may be wrong, let alone proxy objects have their own invariants. Although perhaps implicitly, he meant all objects with the exception of a proxy.
I meant this(your sentence):
And what's the point? If exists an invariant for a method that is not enforced in it? P.S I understood your explanation: an invariant for a particular object does not have to be enforced in the method itself for which it is declared. |
Right. The spec is telling you that the
Proxy objects are free to maintain additional or more specific invariants, but they are definitely still obliged to maintain the invariants specified in 6.1.7.3.
No, he did not.
An invariant isn't something that has to "appear" in any internal method. It's a condition that an object's internal methods must (somehow) satisfy. How they do so is not necessarily going to be obvious. For the case of ordinary objects, the
Great! But if you understand that, then I don't get why you asked:
|
That is, invariants for proxy objects are summed up? The result of [[GetPrototypeOf]] is a step from the proxy algorithm (13) or from the proxy steps of the algorithm (6 and 11) where are [[GetPrototypeOf]] from normal objects used?
If I understand you correctly, then any invariant does not have to be enforced in the method for which it is intended, besides, it does not have to be enforced somewhere else, but it will be enforced where the place is most appropriate to enforced this invariant.
Otherwise, I don’t quite understand that part:
This refers to SameValue (what I wrote in the paragraph above, in this message) |
In the [[GetPrototypeOf]] internal method for proxies, the calls to Other than that, I'm not sure what you were asking.
That's probably an okay understanding of the situation.
I think so, You're saying that if the invariant refers to a specific operation, then you'd expect to see that operation also referenced by the code that enforces that invariant. But no, that expectation isn't warranted, especially when the operation in question in SameValue. Roughly speaking, the first [[Get]] invariant is saying that if property P is a non-configurable, non-writable own data property, then each call to [[Get]] must return the same value (according to the definition of SameValue). This is more-or-less equivalent to saying that any attempt to change the value of P must not succeed -- as long as nothing can change the value of P, then the value returned by [[Get]] will always be the SameValue. But you don't accomplish that by checking whether P's current value is the SameValue as some previous value, you accomplish that by preventing changes to P's value. |
This question was related to
for proxy algorithm [[GetPrototypeOf]]. What is result of [[GetPrototypeOf]]: steps (6, 11) or (13)?
I just do not understand the logic of the specification: why specify a specific operation, and then not enforce it?
Why it was impossible to write it easier? Why is it needed? Maybe she means not the meaning that I put into it?
You said: |
Because in this case, a runtime check would be pointless: it is already provable that the result satisfies the invariant. Runtime checks corresponding to invariant rules are a special and rare case. They are only needed when some part of the algorithm depends on the result of invoking arbitrary user code. So why specify it for all objects? For one, it’s broadly useful to be able to know what reliable facts exist about them. But more importantly, implementations may expose their own exotic objects with their own definitions for their internal object methods. The invariants tell us facts about objects, and it is these facts that will be important for people implementing new exotic objects to understand, because if these facts aren’t true for their object, it’s not a JS object. It’s saying ‘a JS object behaves as follows’. It’s not an operation or an algorithm, it’s a ‘truth’, like in formal logic. |
The invariant applies to the result of the [[GetPrototypeOf]] internal method for all objects. So for a proxy object, it applies to the result returned at 6.a, 10, or 13. And for the proxy object's target object, it applies to the result of the invocations at 6.a and 11 (which are, of course, the value returned by some (possibly other) [[GetPrototypeOf]] internal method).
It is enforced! But you can enforce it without referencing it. I don't know how to make that plainer.
An invocation normally looks like
It means "according to the definition of the SameValue operation in 7.2.10". Or, more long-windedly, "X is the SameValue as Y" means "SameValue(X, Y). as defined in 7.2.10, would return true".
Say you did. If SameValue told you they were different, you'd have to return the previous value (to maintain the invariant). And if they were the same, you could return either, so might as well return the previous. In which case, you'd have no need of the "current" value as a separate value. Just keep the previous value as the current value. I.e. don't allow the value of the property to change. |
Wait for this invariant for proxies, why do you say that it is applied to the result of the [[GetPrototypeOf]] internal method for all objects? And why do you push the target object of the proxy object and the proxy object itself in step 6.a? This is due to the fact that maybe instead of the ordinary object of the proxy object? And therefore you need to apply the invariant for the proxy object as a target?
I meant that the specification does not use the SameValue operation in its common and normal form with arguments, but uses it as an abstract term. In my opinion, this complicates the understanding of the chapter with invariants. This thing needs to be more clearly explained. Or still abandon the term SameValue.
If the specification tries to assure the reader that this operation is used, then it is worth making it more obvious, because the reader may be at a loss that he will not find this operation in the algorithms. Well let's say the specification tells us that this operation is SameValue. But I suppose I can’t understand how it is used if the usual programmer’s call is not used through the name, parentheses and argument passing. What should I imagine to understand?
Well, although you gave a free definition of a SameValue operation. The complete definition of the operation I think is the whole algorithm (including production steps), which provides the name SameValue. Well, that is, again, the specification if I am not mistaken, does not say what the definition of SameValue is. She should say it more clearly, to understand unambiguously what is meant by:
This is your sentence. I already asked about him. But I just do not understand what it is about, even in the context of your paragraph where it is present. Why am I not accomplishing? Do not accomplish what? Invariant?! I do not understand the logical chain in which your sentence stands, specifically I do not understand what the accomplish refers to. |
Because it's not an invariant for just proxies, it's an invariant for all objects. We went over this two days ago.
I don't know what you mean by "push" there.
If I understand you correctly: Yes, the proxy's target object could be (instead of an ordinary object) another proxy object. Or any other exotic object.
It doesn't really matter what kind of object the proxy's target object is: it must enforce all the invariants in 6.1.7.3. So the calls to
I'm pretty sure I disagree. But you're free to suggest changes that you think would improve the spec.
My guess is that such a reader would be at a loss regardless of how obvious we make the connection between
If you can't figure that out yourself, then I think maybe ECMA-262 isn't for you. As currently written, it doesn't "hold your hand" or make everything as obvious as you want. It might improve in this area, but probably not much and probably not soon. But if you don't want to give up on the spec, you could just skip 6.1.7.3. I'd say you only need to understand it if you're adding non-standard exotics to an implementation (or maybe if you're building an implementation for which adding non-standard exotics is a future possibility).
In the original context of that sentence, you can read "accomplish that" as "enforce the first [[Get]] invariant". Here's the logical chain:
|
Wait for the invariant for all to look like this:
The proxy invariant looks like this:
The invariant given by me was taken from a proxy. Why do you then say that it is for all, and not just for a proxy? I misunderstood something?
I meant intersectability, that is, how a proxy object can be in 6.a as well as a ordinary object.
Yes, that's it.
Yeah, I remember the mention of @allenwb that, regardless of the type of object, the invariants from 6.1.7.3 should be used. This means that proxy objects must follow invariants:
But then there is a slight misunderstanding. In fact, the lower two invariants overlap the two upper invariants, because they are the same (but this only works for proxies). And as mentioned earlier, the invariants from 6.1.7.3 are applied to all objects. In this case, how does it work? Do you understand what I mean?
I would also agree with you having full knowledge of the situation, everything depends purely on understanding.
I agree in general, the specification is not easy to read, again if you do not know what is happening in it.
I do not plan to give up so easily :)
Great, well explained here. I have no choice. I have to ask about SameValue again. That is, this operation is not meant in invariants as a standard function that should be called. But as an operation which is implied with meaning. Because we can see an invariant with this operation, but not see this operation where the invariant should be enforced. Right? To comply with the invariant where SameValue is used, do we need to follow the steps of the SameValue algorithm (Question to P.S I don’t like that I have to go back to some questions in a few days and then walk in a circle. I would be happy to ask all the necessary questions on the first day if I knew the situation better. |
The Note in 9.5.1 [[GetPrototypeOf]] doesn't define invariants. (You can't define a normative invariant in a Note.) Rather, it's referring to the invariant defined in 6.1.7.3. As I said above:
I'm not sure I'd agree with all of that, but it's probably close enough.
No. (Lots of explanation to that effect above.)
The invariant is saying that if (hypothetically) you were to compare these two values using SameValue (according to the definition in 7.2.10), then it would return true. But it's definitely not requiring the object to perform that comparison. Going back to the idea of an imaginary auditor checking that every object satisfies the invariants, you can certainly imagine that the auditor would invoke the SameValue operation.
Not asking all the questions on the first day isn't the problem; rather the problem is asking questions that have already been answered. |
That is, this note in 9.5.1 shows a feature of invariants for proxies? But in fact these are the same invariants from 6.1.7.3? That is, for the invariant the sense of the SameValue operation is important - return true if the values match? What is the SameValue definition? This (excluding algorithm steps)?
If this is a definition for SameValue, then read the following invariant:
There are problems with understanding. If we read this sentence and read the operation as a term SameValue, and not as the phrase "same value" (which gives us a sense rather than a name like "XYZOperation"), then based on the definition that I gave above, the returned value by the operation SameValue maybe as The problem is not that I ask questions for which there is an answer, but that I don’t understand them enough. Similar questions come out of it. Believe me before I ask the questions again, I carefully reads the previous answers. |
Hm. I'm not sure what you mean by "a feature of invariants". And the phrase "invariants for proxies" makes me think you still haven't quite understood. But yes, the invariants in the Note in 9.5.1 directly correspond to the [[GetPrototypeOf]] invariants in 6.1.7.3. Like I said before: this Note is telling you that the [[GetPrototypeOf]] internal method for proxies enforces the [[GetPrototypeOf]] invariants that are specified (in 6.1.7.3) for all objects.
Yes.
You can't exclude the algorithm steps. (What do you think you achieve by excluding the algorithm steps?)
That's what we call the operation's preamble. It (hopefully) tells you things that are true of the operation, but it certainly isn't the definition of the operation. In fact, it's often completely superfluous, and many operations don't have one.
Clear enough, I think, and a fair point, but I've already addressed it:
|
@jmdyck
then in 9.5.1 it is specified how the invariant for the proxy object from 6.1.7.3 should be enforced? (Yes, so far this moment is not clear to me using invariants in a note)
I think then I lose the whole point of the operation. Well, it turns out the introductory text of the operation and the operation steps themselves are the definition?
Yes, but the specification is not so written. Well, if logically imagine the meaning of the operation, then I no longer need an explanation for this point. |
It would be more accurate to rearrange that slightly: in 9.5.1 it is specified how (two of) the invariants from 6.1.7.3 are enforced for the proxy object.
Right.
And the clause heading, and any other normative text about the operation. (But the introductory text often says little that you couldn't figure out from the other pieces of the definition.)
If you think it should be, you can request that. I think it's reasonable to expect that readers would understand that just by reading the current text, but if we can make it more obvious at little cost, it might happen. |
Do these invariants (9.5.1) override the invariants from 6.1.7.3 for proxies? (I know what you wrote:
Honestly, I do not know how, I just read and ask questions sometimes. I think there are more literate people, instead of me |
No.
Okay, so do some deduction:
If that seems like a reasonable question, then I don't think you understand what "normative" and "non-normative" mean. Not that that's a crime, but you maybe should have looked it up by now. So, again, no. The invariants noted in 9.5.1 do not override the ones stated in 6.1.7.3. They couldn't possibly. Instead, the
6.1.7.3 doesn't enforce invariants, it states them (defines them, specifies them). So it doesn't make sense to talk about "the enforcing of invariants" changing from 6.1.7.3 to 9.5.1. |
@jmdyck now I will try to make a maximum breakthrough to eliminate all questions and get a clean answer (there will be several references to your answers above).
I do not really understand this. You can visually show the dependency as an internal proxy method of the [[GetPrototypeOf]] object using invariants from 9.5.1 ensures the use of invariants from 6.1.7.3. (Maybe I misunderstood you, read my answer completely before answering this question right away) And seems this quote:
refers to the quote above. Right? Next, your sentence:
What do you mean by directly corresponding? (do not rush to answer, read on)
If we are talking about the internal proxy method of the object [[GetPrototypeOf]] - are the invariants in the note from 9.5.1 additional invariants or specifying for 6.1.7.3? If these invariants are specifying (9.5.1), then it turns out that they are also invariants that maintain 6.1.7.3? Right? (This question looks like it answers your quotes above.) Besides I understand what:
From this it follows that we cannot override normatives by non-normatives. Since the notes are non-normatives.Normatives are mandatory rules to follow. Non-normatives are optional rules, tips, recommendations, may not be follow. If I understood everything correctly, then taking any proxy object we are obliged to follow the rules of |
The note in 9.5.1 is not a rule — it cannot be followed or not followed — it is just descriptive. It’s explaining what the algorithm is achieving. The purpose of these notes is to highlight the relationship between steps in the (normative) proxy exotic object internal method algorithms and the (normative) object invariants. Knowing where the invariants are addressed for proxies is helpful for implementors, but even if the notes were removed, the spec would still be saying the same thing. |
@bathos If I understand you correctly, the note in 9.5.1 explains how the invariant from 6.1.7.3 enforced? |
The phrase "an internal proxy method of the [[GetPrototypeOf]] object" makes no sense. Presumably you mean "the [[GetPrototypeOf]] internal method of a proxy object". And you don't really "use" an invariant, you enforce it, or satisfy it. So you could say: enforcing the invariants from 9.5.1 ensures the enforcing of (two) invariants from 6.1.7.3. But I don't know what you mean by "You can visually show the dependency".
Something I said earlier can't "refer to" something I said later, but they are talking about the same thing.
(Again, that wording makes no sense. It's the [[GetPrototypeOf]] internal method of a proxy object. The fact that you made the same mistake twice suggests to me that there's something wrong with your mental model of objects and internal methods. You should maybe fix that first before trying to understand invariants.)
I'm not sure what you mean by "specifying for 6.1.7.3". Maybe "specializations of 6.1.7.3"? For the first invariant, the one in 9.5.1 is just a rewording of the one in 6.1.7.3. For the second invariant, it's not simply a rewording. The one in 9.5.1, because it refers to the proxy object's target object, is specific to proxy objects. It says what the proxy object's [[GetPrototypeOf]] internal method does to enforce the corresponding 6.1.7.3 invariant. So in this case, the 9.5.1 invariant is, in some sense:
the corresponding 6.1.7.3 invariant. So I don't know what that means in terms of the distinction you were drawing.
Yes. Mind you, following everything else in 9.5.1 will cause you to follow the note as well (i.e., satisfy the invariants in the note).
Some of the wording is unclear, but it's possible that's correct. (But if you mean that the invariants in 9.5.1 (note) are a specification for the [[GetPrototypeOf]] internal method for proxies, that's incorrect.) |
Of course, sorry for my wrong wording.
That's right, I meant that you are talking about the same thing.
No, I thought it wrong, I agree with your assumption above what I meant.
I do not know how to say this correctly on English. But most likely I meant concrete or precise or specialize, if for you the word
Hmm...I don't understand you. What does it mean:
Ok, you can simple replace When I said:
by
Where will additional or specific invariants come from if the specification does not specify them?
By the way, is this related to the quote above? P.S I apologize in advance if I again messed up somewhere with the wording. |
I think "specialize" is best choice: the second invariant in 9.5.1's note is a (proxy-specific) specialization of the second [[GetPrototypeOf]] invariant in 6.1.7.3. (At least, that's one way to think of it. Some people might think differently.)
You aren't required to satisfy the non-normative content of 9.5.1 (the note), but you are obliged to conform to the normative content of 9.5.1 (the algorithm), and in doing so, it will happen that you also enforce the invariants that appear in the note.
9.5.1's note has an example of a more specific invariant (or an additional invariant, depending on your point of view). Someone implementing the proxy object internal methods might find additional invariants not stated in the spec. And someone creating a particular proxy object might have invariants in mind when writing the methods of its handler object. |
Good, but I think you will agree that the words I picked up also fit. At least I see their meaning similar to "specialize." (It was about "concrete" or "precise")
Good clarification, now it became clear.
What does it mean: |
Not all invariants are stated (as such) in the spec mainly in the same sense that when defining what ‘adding two integers’ means, you probably would not bother listing the following invariants about that operation:
The invariants exist regardless of whether they are stated as such. Invariants are just things that are, and must remain, reliably true. The explicit invariants for object methods are an aid to implementors who might introduce new exotic objects because when they do this, they may be operating from ‘outside’ of the ES layer. A summary of all the object invariants in the spec would be (loosely, not precisely) ‘exotic objects must not exhibit behaviors that objects created with ECMAScript source code could not also exhibit’. This is very near to saying ‘all objects must be objects,’ a tautology, but for implementors, having the sum/emergent observable effects of the specified algorithms made explicit is valuable clarification. |
Sure. For example, here's an invariant:
It's not stated as an invariant in the spec, but you can convince yourself that it must hold by looking at the first two steps of the [[GetPrototypeOf]] internal method for proxy objects. But I think you're going off on a tangent that isn't essential to understanding invariants in the spec. |
Hmm, it turns out any step from any algorithm can be written as an invariant. If this is so, then why is something specified as an invariant, but something is not specified (as in your example) What does it make sense? And judging from this quote:
It can be concluded that: an object may be created which does not correspond to the invariants from the specification. Does this mean that it follows the invariants that are specified by the implementers of the object? And whether it is connected with:
That is, can any proxy objects (or any object) that do not follow the specification define their independent invariants?
Some details also valueble. |
I think it is important to remember that one implementing the spec isn't expected to write their code out in the exact steps listed in the spec. The point of the spec is to convey the behaviour of a conforming implementation. In the case of this invariant you keep bringing up about object behavior, the point is to communicate the intent of the specification, which is something a series of algorithm steps cannot do. |
That’s not what that paragraph is saying. It’s saying e.g. Node is free to ship with Buffer as a builtin, or to add new properties to intrinsic objects, etc. It doesn’t concern object internal methods. |
Yes and no. It's probably another non-essential tangent.
If you took even a relatively small algorithm and tried to express all of its normative requirements as a set of invariants, it would be harder to write, harder to read, and harder to implement. Conversely, if you took the invariants of 6.1.7.3 and tried to express them as a set of algorithms, you would probably over-constrain implementations.
Nope, you can't conclude that. You don't seem to have grasped what @allenwb said 15 days ago:
Please understand that "all objects" means all objects. No exceptions!
If the implementers choose to document the semantics of the object via invariants, they can do so. But regardless, it must satisfy the invariants of 6.1.7.3.
It seems to me that the sentence you quoted already answers your question. But in case it helps to have it reworded yet again: It depends what you mean by "define their independent invariants". If you mean that the total set of invariants they enforce is completely disjoint from the invariants of 6.1.7.3, then no, that's not allowed in a conforming implementation. If you mean that the total set of invariants contains all the ones in 6.1.7.3, and in addition some that aren't in 6.1.7.3, then yes, that's allowed. (I'm assuming that, by "do not follow the specification", you mean "are not defined by the specification".) |
@jmdyck
Could you clarify why yes and no?
Yes, I agree that invariants are harder to read, write than algorithms and even more so to implement. But you said that if you take the invariants from 6.1.7.3 and try to express them as algorithms, then I would: |
I maybe could, but since I think it's a non-essential tangent, I'm not going to try.
Well, for instance, consider:
How would you convey that requirement as part of an algorithm without specifying which object (or null) must be returned? |
If I understand correctly, then we can express it as follows:
You interested me, please, I would like to get an answer to this. |
So then the interesting question is: how does the algorithm give |
@jmdyck probably through any steps that should precede this line |
Of course. But how does it get set in a way that doesn't over-constrain implementations? |
@jmdyck I do not really understand what is meant by: |
In this context, to over-constrain implementations is to require more of them than the 6.1.7.3 invariants do. I'm saying that if you tried to express the requirements of those invariants as a set of algorithms, those algorithms would probably express additional requirements (constraints on behavior). This could cause some conforming implementations to be deemed non-conforming, breaking backwards-compatibility. |
That is, more steps in algorithms in relation to invariants
That is, for some algorithms, some requirements (features) may arise, in view of which it will be necessary to change the steps of the algorithm to enforce the invariants (and these changes or differences in steps can differ greatly from algorithm to algorithm)? |
It's not about the number of steps.
This isn't about requirements arising from features, it's about requirements being incorrectly introduced as a by-product of trying to replace invariants with algorithms.
I was talking about a hypothetical spec in which the 6.1.7.3 invariants don't appear, so I'm not sure why you're talking about enforcing the invariants.
No. Over-constraining implementations isn't a style to be used, it's a mistake to avoid. Anyhow, this whole tangent of hypothetically replacing invariants with algorithms (and why that's a bad idea) is not important to understanding the spec. You might want to think about wrapping up this issue. |
@jmdyck Well, I agree, you have already answered my main questions. But I would like to separately communicate with you via email or maybe some kind of social network to still find answers to questions that I could not find out here. |
In the specification there is such a term as "invariants". As I understand it, it is used for assertions in algorithms that must be enforced. I noticed that the specification in chapter 6.1.7.3 says to which objects these invariants are applied: to ordinary and standard exotic objects. But exotic proxy objects are also casually mentioned there, the sentence sounds like:
I honestly do not quite understand what specification wanted to say this proposal. Can you explain this? If you can obviously somehow demonstrate this sentence would be great.
Now let me take the invariants for the [[Get]] internal method:
The first invariant is interesting here.
...then [[Get]] must return the SameValue as V
. SameValue has 2 parameters, and there are no arguments for the transfer. How to understand this?The text was updated successfully, but these errors were encountered: