Open jgraham opened 2 years ago
I'm inclined not to throw exception in such a case, or in case of extended values like:
NullValue = {
type: "null",
value: "SOME_VALUE"
}
My motivation is the following: do we want to restrict any additional fields to ScriptTarget
, or just having realm
and context
or sandbox
together? And the first seems an overkill, and the I'm not sure how the second can be specified.
In general, we can try hard to predict what exactly user wants, and if they made a mistake, but the only way to be almost sure is to restrict all the extensions. I expect our users to know what they do, as long as they chose to send commands directly, instead of using some libraries.
This problem also reminds me strongly of distinguishable dictionaries in Web IDL. There, unions of dictionaries aren't allowed, because type testing would require checking the object properties.
In BiDi, one fix would be to always use different parameters for these target types. But that's not very ergonomic I suspect.
If we use structural typing, the behavior I think would make sense is that exactly one of context
or realm
needs to be present, and beyond that we don't care about overlap in field names. I think this would have to be written has a helper algorithm.
Would using a type
field be an option?
... but it seems likely that the user made an error in that case and we should report that rather than silently resolving the ambiguity.
Actually, it could be not an error, when user reuses the script.getRealms
command result.
I strongly want to avoid the situation where we have lots of optional parameters where it's required specify at least one (and not all combinations of > 1 make sense).
That actually seems the same as saying "you can specify context
or realm
, but not both, and then any other fields are fair game, but they might be ignored"; afaik we can't specify a negative condition in CDDL, so there's basically no difference between writing
Target = {
?realm: Realm,
?context: BrowsingContext,
?sandbox: text
*text => any
}
and writing
RealmTarget = {
realm: Realm,
*text => any
}
ContextTarget = {
context: BrowsingContext,
?sandbox: text,
*text => any
}
Target = RealmTarget // ContextTarget
the only difference is in exactly what text you need to write to post-validate the data after schema validation passes.
Would using a
type
field be an option?
If people strongly feel that these need to be extensible this would be my preferred option (just always using named types and never structural types). But there is a tradeoff in terms of verboseness in the common case.
We do have more or less same example with deserialization. If handle
is there, all other fields are ignored, even if they don't match the handle
object.
The Browser Testing and Tools Working Group just discussed Clarify extensibility rules
.
Do we want to being able re-using values received from the server, e.g. script.Source
or WindowRealmInfo
?
@jgraham @shs96c @foolip ?
I think it's important that it's possible to use values from one command or event as the argument for another, without requiring them to be massaged into some other shape, in particular removing extra fields that are going to be ignored.
Concretely, the RealmInfo
from script.realmCreated
and the BrowsingContextInfo
from browsingContext.contextCreated
should both be possible to use for script.evaluate
. Expressing this in a typed language might require some work beyond just transcribing the CDDL, perhaps base types that have just the required fields and nothing else.
I don't think we should return things like this to the client however.
Another concern is what clients should do. Currently where there's an ambiguous case clients, unlike browsers, have to make up their own rules on how to handle it. For example, if a client gets back something from script.evaluate
that has both a result
and an exceptionDetails
field, what should they do? There's currently nothing in the spec that allows a browser to send both, but if the return type is an enum and each varaint is considered extensible then a client has to deal with the possibility somehow.
On the subject of allowing a client to take a value from an event or command result that's a super-set of the payload for some other command and provide that directly, I worry that kind of reliance on duck typing / type punning is going to make it more complex to extend the protocol in the long run. It means that if we have some set of results and events that return data that's compatible with being used in the parameters to any other set of commands, any future changes to the spec have to maintain that compatibility i.e. we can't add a new field to any of the result/event types that would alter the behaviour of any of the commands that could previously accept that type. So as a concrete example, if people are directly using a script.RealmInfo
result of script.getRealmInfo
as the value for the target
field of script.evaluate
, we can never add a type
field to the script.Target
type, unless it means exactly the same as in the script.RealmInfo
type.
The Browser Testing and Tools Working Group just discussed Clarify extensibility rules
.
For compatibility reasons we've had an understanding that we want to allow commands and responses to be extensible. In the CDDL this is handled with boilerplate in the definitions like:
Which amounts to ignoring unknown fields.
However we have not been consistent about adding this in all the definitions.
This recently came up in the context of the
Target
type, which is defined asThe question was: should it be allowed to have something that matches both the
RealmTarget
production and theContextTarget
production? In that case the behaviour is well-defined (because the prose says to first check if it matchesContextTarget
), but it seems likely that the user made an error in that case and we should report that rather than silently resolving the ambiguity.So, how should we handle this in general? Extensibility is useful and required in some cases. But it's not clear if we need it for every type.
Technically, the problem here is that we're hoping to rely on structural typing i.e. we distinguish the target types by the fields they have rather than by name. In contrast for commands and responses where we clearly do want extensibility each type is explicitly named, so there's no possibility of confusion.
So that suggests a general rule: if we want to allow a type with multiple variants to be extended by clients we should always provide an explicit name for each varaint. If there's no explicit name we should not allow additional fields in that type.
Does that sound like a reasonable approach that meets our use cases? And if it does, are we happy with
Target
being non-extensible, or should we add an explicit type field?