[heycam/webidl] Guidance requested on specifying an unusual pattern from Streams in Web IDL (#819)

[Streams](https://streams.spec.whatwg.org/) would like to [move to Web IDL](https://github.com/whatwg/streams/issues/963). One particular pattern we've employed is unusual and I'd like help from the Web IDL community in figuring out what we should do about it.

In particular, the pattern in question is the queuing strategy classes, e.g. [`CountQueuingStrategy`](https://streams.spec.whatwg.org/#cqs-class). These are intended to be basically convenience factories for objects of the form `{ highWaterMark: number, size: function }`, used like `new ReadableStream(..., new CountQueuingStrategy({ highWaterMark: 1 }))`.

This manifests currently as them having a data property `highWaterMark`, and a `size()` semi-method. The `highWaterMark` can transition fairly easily to a Web IDL `readonly attribute`/JS getter-on-the-prototype. The tricky one is our `size()` semi-method. I say semi-method, because it intentionally does not use its `this` value.

This no-this-value property is something we want to preserve, if possible. The streams machinery currently does not call these functions with a this value. It could be changed to, but as @ricea says,

> I don't want to give up on calling size as a plain function. The principle that it is a pure function is important to the mental model of streams. Making it a method gives the implication that it can be stateful.

Stepping back a bit, I think it was kind of a mistake to make these queuing strategies into classes. They're really more like "factory functions for dictionaries". Moving to a Web IDL framework makes this more apparent. Anyway, how do we move forward? We have a few options (some previously discussed in https://github.com/whatwg/streams/issues/1005) for specifying this within the framework of Web IDL:

- Behavior preserving:

  1. Use "custom bindings", i.e. some prose which installs such an unusual method on the prototype manually, outside of the Web IDL system. Or add some kind of normative monkeypatch in the Streams spec saying "ignore these parts of the Web IDL algorithm". Fairly icky, but at least nobody will be tempted to copy us. (In practice I would expect implementations to use the following strategy under the hood, even if we specced this one.)

  1. Introduce an extended attribute to Web IDL, e.g. `[NoThis]`, which removes the brand check from methods. Straightforward, but people might abuse this. Maybe we could call it `[LegacyNoThis]`?
  
- Behavior changing:

  1. Specify `size` as a `readonly attribute Function size;` which returns the same function on all class instances. This changes the prototype property from a data property to an accessor, and it makes `const size = CountQueuingStrategy.prototype.size` throw. Neither of these consequences are too bad.
  
  1. Introduce an extended attribute to Web IDL, e.g. `[LegacyAllowNew]`, which allows methods to be called even with `new`, and not throw. Then we could do something like
     ```webidl
     dictionary CountQueuingStrategyInput {
       any highWaterMark;
     };
     dictionary CountQueuingStrategyResult {
       Function size;
       any highWaterMark;
     };
     partial interface mixin WindowOrWorkerGlobalScope {
       [LegacyAllowNew] CountQueuingStrategyResult CountQueuingStrategy(optional CountQueuingStrategyInput input);
     }
     ```
     
     Here we are assuming that it is not going to be sufficiently web-compatible to start throwing on `new CountQueuingStrategy()`, since currently you can only call it *with* `new`.
     
     This would change `CountQueuingStrategy.prototype` from its own object into just `Function.prototype`. And it would introduce another legacy extended attribute. But it has the nice advantage of actually fitting the mental model.

  1. Start treating `this` as a method, including brand checks, despite @ricea's misgivings. I want to include this here for completeness in case the Web IDL community does not agree with us on the mental model.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/heycam/webidl/issues/819

Received on Sunday, 3 November 2019 22:16:12 UTC