Skip to content
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

Represent objects with both specified and unspecified members #568

Open
saschanaz opened this issue Jun 19, 2018 · 12 comments
Open

Represent objects with both specified and unspecified members #568

saschanaz opened this issue Jun 19, 2018 · 12 comments

Comments

@saschanaz
Copy link
Member

saschanaz commented Jun 19, 2018

I've seen specs that use object to represent partially specified types:

https://www.w3.org/TR/web-animations/#the-sharedkeyframelist-interface

// `object` here really means:
// (sequence<Keyframe> or PropertyIndexedKeyframes or SharedKeyframeList)
// as noted in https://www.w3.org/TR/web-animations/#processing-a-keyframes-argument
[Constructor (object? keyframes)]
interface SharedKeyframeList {
};

http://w3c.github.io/webrtc-pc/#rtcstatsreport-object

[Exposed=Window]
interface RTCStatsReport {
    // `object` here really means `RTCStats`
    readonly maplike<DOMString, object>;
};

Tools e.g. TSJS-lib-generator have to manually override those objects.

Can we get a better way to spec those types in IDL?

@Ms2ger
Copy link
Member

Ms2ger commented Jun 19, 2018

I don't understand why they don't use the types you suggest instead; can you elaborate?

@saschanaz
Copy link
Member Author

saschanaz commented Jun 19, 2018

I don't understand why they don't use the types you suggest instead

The WebRTC spec defines RTCStatsReport as:

An RTCStatsReport object is a map between strings that identify the inspected objects (id attribute in RTCStats instances), and their corresponding RTCStats-derived dictionaries.

The RTCStats-derived dictionaries are defined in a separate spec by dictionary inheritance.

// The base dictionary in WebRTC
dictionary RTCStats {
    required DOMHighResTimeStamp timestamp;
    required RTCStatsType        type;
    required DOMString           id;
};

// The "Identifiers for WebRTC's Statistics API" spec shows several subdictionaries
dictionary RTCRtpStreamStats : RTCStats {
    unsigned long      ssrc;
    DOMString          kind;
    DOMString          transportId;
    DOMString          codecId;
    unsigned long      firCount;
    unsigned long      pliCount;
    unsigned long      nackCount;
    unsigned long      sliCount;
    unsigned long long qpSum;
};

dictionary RTCCodecStats : RTCStats: {
  // ...
};

// ...

So the RTCStatsReport is expected to include those dictionaries as it is, not reduced as RTCStats.

const rtcStatsReport = await receiver.getStats();
rtcStatsReport.get(key).ssrc // not in base RTCStats but should exist when appropriate

Edit: The keyframes case is different that it even has no subdictionaries; Any CSS property names should be able to be represented as dictionary field names.

@Ms2ger
Copy link
Member

Ms2ger commented Jun 19, 2018

Looking at https://heycam.github.io/webidl/#es-map-get-has, I think the WebRTC spec could be written in a way that would preserve the sub-dictionaries' properties. (Unfortunately, the spec has so much hand-waving that there's no way to tell what's supposed to be going on.) It wouldn't work for read-write maplikes with derived dictionaries, but I guess that problem is not specific to maplikes.

I don't know what's going on with the keyframes case; too much prose.

@saschanaz
Copy link
Member Author

saschanaz commented Jun 19, 2018

I don't know what's going on with the keyframes case; too much prose.

dictionary Keyframe {
    // ... property-value pairs ...
    // i.e. DOMString propertyName
    double?             offset = null;
    DOMString           easing = "linear";
    CompositeOperation  composite;
};
// This constructor receives `sequence<Keyframe>`, but specced as `object`
new SharedKeyframeList([
  { transform: 'translateY(0px)' }, // a key-value pair not specced in Keyframe, but has a meaning
  { transform: 'translateY(-300px)' }
]);

The spec's algorithm gets the ES object, run the ES-to-dictionary conversion explicitly, and then again extracts remaining fields from the original object.

@Ms2ger
Copy link
Member

Ms2ger commented Jun 19, 2018

Wow, who came up with that?

@bzbarsky
Copy link
Collaborator

Web IDL is meant to represent patterns that are:

  1. Common.
  2. Encouraged.

People can define arbitrarily complex processing of input, of course; that's what the any and object escape hatches are for.

In this case, we have two specs that both use object, but they're doing completely different processing on them. How would you want to represent this in IDL other than as object?

@saschanaz
Copy link
Member Author

IMO the issue there is that the ES-to-dictionary algorithm ignores any unspecified fields. If we have some way to get the unspecified fields without using object, that would work.

@bzbarsky
Copy link
Collaborator

Above we have two use cases described:

  1. The webrtc one. This has effectively a union of dictionaries as a return value. A union of dictionaries is not expressible in idl, so it ends up using object. To produce the object, it takes whatever dictionary it has (which varies based on the map key string) and converts it to an object. There's no "unspecified fields" involved.

  2. The keyframe case. That case is basically trying to avoid hardcoding a list of names, for efficiency reasons. The option of just doing a [[Get]] for every CSS property name by listing them all in the dictionary was in fact considered, and decided to be too slow.

This could be addressed by something which acts like a dictionary but also snapshots the set of property names and values on the object or something. But we have exactly one use case so far, and it's not clear that anyone else will want to do this, and if so whether they would want it to work the way the keyframe case does (e.g. ignoring prototype properties).

@saschanaz
Copy link
Member Author

Adding WebCrypto case which also uses object for a union of dictionaries:

[SecureContext,Exposed=(Window,Worker)]
interface CryptoKey {
  readonly attribute KeyType type;
  readonly attribute boolean extractable;
  readonly attribute object algorithm; // union of subdictionaries of KeyAlgorithm
  readonly attribute object usages; // just returns a sequence.
};

@bzbarsky
Copy link
Collaborator

Right, for the "union of dictionaries" case as a return value, object works ok. The amount of spec prose you have to write in this case is the same as if you actually allowed unions of dictionaries in IDL, right?

@saschanaz
Copy link
Member Author

The amount of spec prose you have to write in this case is the same as if you actually allowed unions of dictionaries in IDL, right?

My point is for automation and tooling rather than spec authoring itself, but probably yes.

Today I saw that Permissions API also uses object to receive a union of dictionaries:

[Exposed=(Window,Worker)]
interface Permissions {
  Promise<PermissionStatus> query(object permissionDesc);
};

@Ms2ger
Copy link
Member

Ms2ger commented Jan 16, 2019

Note that the union of dictionaries case is also filed in #57.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants