Browser-compat-data: How to represent 'mixins'?

Created on 5 Oct 2017  Â·  35Comments  Â·  Source: mdn/browser-compat-data

Mixins are bits of API that are defined once and implemented by several interfaces.
E.g. (fictive)

Mixin.method1
Mixin.method2


Interface1 implements Mixin means:
Interface1.method1 and Interface1.method2 are implemented.

Interface2 implements Mixin means:
Interface2.method2 and Interface2.method2 are implemented.

This is used in spec to describe once methods/properties that are implemented by several interfaces.

Mixins are invisible to the users, and different interfaces can implement these methods at different moment, completely and incompletely, and with different bugs or limitations. Mixins are transparent to the user.

Mixins can go away or be added in the spec, without having an impact on the developer using them.

MDN shows mixins only to avoid duplication (or triplication) of articles [and the nightmare of keeping them coherent]. Mixins are blended in the interface they appear like a regular property or method in the sidebar and in the list in the main text.

How to represent them?

data question

Most helpful comment

Now I think I'm more for removing mixins. That way:

  • mdn-bcd-collector doesn't need to care about mixins
  • No complex algorithm needed to create a support table
  • Contributors won't be confused

I still can write code for my use case to track mixin items in BCD, so nothing will be lost.

All 35 comments

I propose to hide mixins from the BCD. We put the method and the compat data directly in the interfaces that implements the mixins.

This has 1 drawback, MDN needs to do some magic to show a summary table on a mixin page as it needs to know which interfaces implement the given mixin. It has this information in the {{InterfaceData}} macro (see https://github.com/mdn/kumascript/blob/master/macros/InterfaceData.json ). We likely will need a new macro for these pages.

This is an important issue for Window and the *GlobalScope interfaces. (As well as a few others like AudioContext and AudioWorklet)

I think I agree to hide mixins.

But what does this mean in practice?

Taking the example of https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/atob


Not using mixins: This would be two different compat data entries (in different files). This looks closer to what web developers see.

  • api.window.atob
  • api.worker.atob

Using mixins: As there is different compat data for different contexts, you would probably end up with sub features. This has the benefit that all data for "atob" is together in one tree or one file.

  • api.WindowOrWorkerGlobalScope.atob.

    • window_context

    • worker_context



On MDN: The rendered table on https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/atob should somehow display the compat info for both contexts. We'll need to see how we could do this when not using mixins. (it seems easier with what we can do now if we would use mixins in the compat data, too).

Aside: Imo the MDN page is not very good. It mostly only gives a code example in the window context. I think we need to get better there. Generally "WindowOrWorkerGlobalScope" is invisible to web developers and rather cryptic (on MDN and in BCD). All we want to say somehow is that this is for windows and workers...

__About the aside__: yes, I agree with this. This comes from the fact that it wasn't a mixin, then it became one and we did the change without rewriting the page.

Note that we have cases where a method was in a mixin, then outside a mixin (mixin removed); or in a mixin, then in another, then back on the interface while the mixin was kept for this method and used for 2 other interfaces (!).
Mixins come and go very easily as they are a way to make the spec more readable, or less error-prone. It is an editorial technicality for spec writers and is not discussed as feature change.

__On MDN__: if we use mixin, we likely need to create a specific macro that looks at {{InterfaceData}} to know which interface use the mixin, to find the correct compat info for the compat table.

Ok, I think the plan could be:
Note: I'm using this to track progress on the issue, as this imply numerous PRs.

  1. [ ] Migrate InterfaceData to mdn/data repo

    1. [ ] Make mdn/data loaded by kumascript. In progress in mdn/kumascript PR#343 .

    2. [x] Move content of InterfaceData into mdn/data. Details in mdn/data PR#122.

    3. [ ] Create tests for macros using {{InterfaceData}}:



      • [ ] APIRef


      • [ ] FirefoxOSApiRef


      • [ ] InheritanceDiagram


      • [ ] InterfaceOverview



    4. [ ] Update the macros using it to use the one on mdn/data:



      • [ ] APIRef


      • [ ] FirefoxOSApiRef


      • [ ] InheritanceDiagram


      • [ ] InterfaceOverview



    5. [ ] Remove InterfaceData from mdn/kumascript

  2. [ ] Create CompatMix in mdn/kumascript making use of InterfaceData
  3. [ ] Update contrib documentation w/ mixin information
  4. [ ] Migrate compat data for mixins (will last a long time!)
  5. [ ] Update MDN pages for mixin properties and methods not to be specific to a specific interface.

@Elchi3, what do you think?

Sounds good to me, thanks for working on this. Good to see data migrated into the proper repository.
Renaming is needed, because this really is "API inheritance data" or similar.

I wish I'd seen this conversation sooner, since I disagree. I think we need a way to have a unified place for the mixin information in the data store so we don't have to update this stuff in multiple places like we do if we include the implemented mixin methods and properties within each individual interface.

Then a bit of pipe dream thinking: On MDN, we then create the pages for the mixin but we don't show them directly (that is, they're not linked on overview pages, and they might even be noindex). Instead, they get automatically injected or transcluded within the hierarchy of pages under each interface, with the appropriate names subbed in.

This would require some macro and/or platform work, though. But from a user data maintenance standpoint, it would be much better, and from a UX standpoint on MDN, it would be amazing.

In fact, a mixin is not necessarily implemented at the same time in each interface. So it means that we can not have a unique BCD value for a mixin: it needs to be at the interface level.

As a mixin is not user-facing, we also have renaming and removal of mixins happening all the time in the specs. It is an editorial thing at the spec level.

There is no way, and no concrete use, to keep track of these renamings or removals as it has 0 consequences, and is invisible, for web developers. And having dealt (more or less successfully) with the URL interface, it can be a nightmare for writers: lots of work for no actual benefits for the reader. Let's avoid this problem.

So I feel strongly in favour of the rule: no mixin listed separately in BCD.

My only remaining question or concern on this, then, is what if anything we want to do about making sure people can understand why these things are missing if they look at the WebIDL for an interface that's based in part on a mixin.

I would like to point out that it can be confusing not to specify where a sub-feature comes from.

For example, I recently edited the HashChangeEvent article. Before, it had listed target, type, bubbles and cancelable as properties (not compat data though), even though these originate from the parent interface Event – which I found quite confusing.

If we would not mix and list mixin separately, we could add includes <code>FooMixin</code> as a sub-feature.

If we do mix, we should maybe make it clear in the description where the feature comes from, e.g.: the sub-feature name coming from the mixin CredentialUserData (see #2275) would be described with <code>CredentialUserData.name</code> in FederatedCredential and PasswordCredential (which include the mixin).

When poking around in https://github.com/foolip/mdn-bcd-updater, I've found that the use of mixins in the BCD model results in some strange situation. As @teoli2003 points out things may not be implemented at the same time on the different interfaces that include a mixin and it didn't take long before I stumbled on a real such case:
https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/fullscreenElement

Prefixed variants of this API have existed for a very long time on Document, but the unprefixed ones will be available on Document and ShadowRoot. This can't be easily represented as it is.

The issue of base classes came up in https://github.com/mdn/browser-compat-data/pull/3368#issuecomment-462409852 and this is information that could be extracted from Web IDL. Similarly, information about mixins could be extracted. I'd be happy to write some scripts for it if that would help move this discussion along.

Here's a related issue that @Elchi3 asked me to open. #3441

For reference, usings scrips in https://github.com/foolip/mdn-bcd-updater and comm on the command line, I've produced lists of APIs in BCD but not IDL and IDL but not BCD.

That's with mixins and partial interfaces applied on the IDL side. Much of the lists are explained by BCD using mixins for some things and some things not. With some script tweaking I made IDL with mixins but no BCD and that list is a bit shorter, but it has stuff like NavigatorID.vendor because that particular mixin has been flattened into Navigator in BCD.

One could mostly work around the problems, but I think this will be an impediment to improving the data quality.

I see some similarities to https://github.com/mdn/browser-compat-data/issues/3463, in that one could try to represent the mixins in the data model and do something in the presentation similar to what one could for members of parent interfaces.

@Elchi3 who has to make a decision on this? Whatever is decided, how would one roll out a change that either deletes a lot of mixins or adds a lot of mixins?

MDN is inconsistent and BCD followed these inconsistencies to not block on data migration. Sometimes we document mixins that specs invented or sometimes people used the mixins the browser vendors invented for convenience. All this changes at different times in specs and browsers as new conveniences are needed.

one could try to represent the mixins in the data model and do something in the presentation similar to what one could for members of parent interfaces.

My understanding is that for web developers they are an implementation detail (almost always I think).
Also, I think it is going to be really hard to have them reliably in a data model for BCD or in good content structures in MDN API docs. We probably want to follow mixins from specs, but even these get often re-arranged for conveniences. So, I'm not sure I buy that they would also bring us conveniences like they bring to spec authors and implementors if we need to move around docs whenever specs move around things as well.

That said, I'm leaning towards not having them exposed to web developers here or on MDN, but I would like to do some research to make a better call. Ideally, we want a tool that accepts WebIDL and spits out MDN URLs and BCD paths to create with rules coded in there. So, if we decide one rule (of many rules likely) is that mixis are bad and we flatten them, the tool takes that into account and presents a structure for MDN and BCD from a given WebIDL snippet. Only this way we create reliable structures and not random structures a contributor to MDN web docs decided to use and BCD then inherits from.

One could mostly work around the problems, but I think this will be an impediment to improving the data quality.

This is on point, so I agree we need to solve this.

@Elchi3 who has to make a decision on this? Whatever is decided, how would one roll out a change that either deletes a lot of mixins or adds a lot of mixins?

The MDN content team lead by @chrisdavidmills as I think I would like to follow what MDN decides. BCD and MDN docs both want to expose useful information about web apis to web developers, so I don't want to make a call for BCD alone.

Making the changes is likely a lot of work, but if we have a reliable ruleset agreed on (this is the hard part), we can see how to address this and audit BCD and MDN against these rules and then piece by piece get things sorted. (BCD is easier as it is in git and as we have tooling to lint etc).

@Elchi3 not representing mixins in the BCD model at all sounds good to me and I'd be happy to work in that direction.


These are the 69 mixins that exist in specs (from reffy-reports) today:

AbstractWorker
AccessibilityRole
Animatable
AnimationFrameProvider
AriaAttributes
BluetoothDeviceEventHandlers
Body
CanvasCompositing
CanvasDrawImage
CanvasDrawPath
CanvasFillStrokeStyles
CanvasFilters
CanvasImageData
CanvasImageSmoothing
CanvasPath
CanvasPathDrawingStyles
CanvasRect
CanvasShadowStyles
CanvasState
CanvasText
CanvasTextDrawingStyles
CanvasTransform
CanvasUserInterface
CharacteristicEventHandlers
ChildNode
CredentialUserData
DocumentAndElementEventHandlers
DocumentOrShadowRoot
ElementContentEditable
ElementCSSInlineStyle
FontFaceSource
GenericTransformStream
GeometryUtils
GetSVGDocument
GlobalEventHandlers
HTMLHyperlinkElementUtils
HTMLOrSVGElement
LinkStyle
NavigatorAutomationInformation
NavigatorConcurrentHardware
NavigatorContentUtils
NavigatorCookies
NavigatorID
NavigatorLanguage
NavigatorNetworkInformation
NavigatorOnLine
NavigatorPlugins
NavigatorStorage
NonDocumentTypeChildNode
NonElementParentNode
ParentNode
Region
ServiceEventHandlers
Slotable
SVGAnimatedPoints
SVGElementInstance
SVGFilterPrimitiveStandardAttributes
SVGFitToViewBox
SVGTests
SVGURIReference
SVGZoomAndPan
TextDecoderCommon
TextEncoderCommon
WebGL2RenderingContextBase
WebGLRenderingContextBase
WindowEventHandlers
WindowLocalStorage
WindowOrWorkerGlobalScope
WindowSessionStorage

Of those it looks like 21 of those are in BCD:

Assuming that pages like NonDocumentTypeChildNode will have to be updated either not include compat tables at all or point to Element + CharacterData, here's a transition plan I think could work:

  1. Flatten the mixins into the interfaces that include them in BCD. When reviewing, careful attention to notes will be needed.
  2. Optionally, add a lint/warning preventing the mixin JSON files from being edited further.
  3. Publish BCD, update the pages pointing to the mixins.
  4. Remove the mixins from BCD.

WindowOrWorkerGlobalScope is a good example where attention to notes will be needed. One note says "fetch() now defined on WindowOrWorkerGlobalScope mixin" which probably means fetch() was exposed to workers then, but that's not clear.

That's also a bit of special case in that it would split window or worker-exposed APIs across Window and the multiple *WorkerGlobalScope interfaces. It probably makes more sense for web developers to visit https://developer.mozilla.org/en-US/docs/Web/API/fetch (now redirects) and see the support in various contexts in a single table.

@Elchi3 any thoughts on how you'd like to deal with the list in https://github.com/mdn/browser-compat-data/issues/472#issuecomment-465522306?

So, here are my thoughts on this:

  • I agree that readers don't care about the mixins and want the stuff just listed in the interface they're part of.
  • However, I think it's important organizationally and structurally to have the mixins maintained separately. It will be easier to maintain if they're kept in their own place, so that if they move around, or specs change hands or whatever, you can deal with it more quickly. It also helps keep the size of the base interface file down to a more manageable length.
  • This is especially crucial for mixins that are used by more than one base interface, such as WindowOrWorkerGlobalScope. We should not have to manually update the documentation for a given method or property in two interfaces if there are changes to a mixin. This invites discrepancies and content bugs.
  • I think, therefore, we should keep mixins in their own JSON files for BCD, but that mixins' contents should be displayed on the site within the context of each class that inherits them.
  • Therefore, I believe we need to complete the process of writing code to automatically construct the overview pages, indices, and so forth, so that they get automatically blended into the main class for display on MDN.

The InterfaceData.json file already has the most critical part of the data we need: the list of things implemented by each interface (both mixins and base class). This is contained in the impl field of the records there. For example, consider the record for Navigator:

    "Navigator": {
      "inh": "",
      "impl": [
        "NavigatorID",
        "NavigatorLanguage",
        "NavigatorOnLine",
        "NavigatorContentUtils",
        "NavigatorStorageUtils",
        "NavigatorFeatures",
        "NavigatorGeolocation",
        "NavigatorBattery",
        "NavigatorDataStore",
        "NavigatorMobileId"
      ]
},

I do feel that we should add to mixins listed in the InterfaceData.json file a pointer back to the interfaces that inherit them, too. I don't believe we currently have that.

With this information in hand, we can easily update our compatibility table generator to include the data for the mixins as appropriate, such as by including all of the contents of each of them in the table generated for the Navigator interface itself.

Then we have to look at where we put the documents themselves. For the sake of cohesiveness, I think they should be maintained separately, perhaps just like they are now. Using automatic inclusion of the content into TOCs and indices should do a good job of integrating the content into the inheriting interfaces.

If it's a problem that we the lack the ability to use breadcrumbs to back up into the parent, or the fact that the mixin would not know how to refer to itself based on the parent that the user clicked into it from, there ought to be a technical solution to it. For instance, we could have the macros that build these lists add a parameter to the links that lets the target page know which interface it's being looked at as part of. Then we'd just need a way to have a variable of sorts on the page that would sub in that information when presenting the contents. Something like that.

Not all of this is easy, but it's not tremendously difficult either, and I think we can greatly improve usability for both readers and contributors.

We have made vague attempts at this in the past, and I have my in-progress InterfaceOverview macro that I never get time to work on, whose goal is to do exactly this kind of thing. It doesn't yet deal with mixins, but totally could.

@a2sheppy maintaining a list parent interfaces and mixins should be quite straightforward as it can be derived directly from the Web IDL in reffy-reports. I tweaked a script to generate it here:
https://gist.github.com/foolip/237f1aa6e824620fe7b649613896a8e3

The Navigator section looks a lot like you suggested.

However, as you say, readers probably don't care about mixins. It seems to me there are some challenges in maintaining compat data for mixins and then flattening that into the real interfaces in the support tables that people see/use. How should one deal with the cases where the support status on the real interfaces aren't the same? As I mentioned in https://github.com/mdn/browser-compat-data/issues/472#issuecomment-462717732 this does happen, most of the members in https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot#Browser_compatibility are like this. It will also be the case for many APIs in https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope#Browser_compatibility which predate worker support in browsers.

I was thinking about this again. It occurs to me that this should not be called, 'How to represent mixins?', but 'How to disambiguate mixins for multiple use cases.' Clearly, a single method of handling mixins is not possible, hence the age of this ticket.

Here's an example of why I'm not a fan of having MDN mirror IDL files too closely. In #3949 is a case where things implemented on Document in one browser are documented on a mixin in another (Chrome in this case).

I have just come across another case where mixins make it hard to represent the real compat story correctly. From https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/dataset#Browser_compatibility one would infer that IE11 would have both HTMLElement.prototype.dataset and SVGElement.prototype.dataset, but in fact it's only supported on HTMLElement.

(I have no new suggestions for how to resolve this issue, though.)

Could we add a field that indicates an interface includes a mixin, and then still allow a duplicated item in the interface to override?

  • api.Window.__mixin === ["WindowOrWorkerGlobalScope", ...]: Import items from mixins by default in MDN
  • api.WindowOrWorkerGlobalScope.isSecureContext: The item that will be shown by default
  • api.Window.isSecureContext: Exists when we want to override the support status
  • api.Window.isSecureContext.status === "mixin": Way to indicate this is overriding a mixin item?

@saschanaz something like that sounds workable. What rule would you suggest for how to represent that there are differences in support in the concrete interfaces? Say we have three interfaces A, B and C and a mixin M. Some member of M appeared at different times in all of A, B and C. In this case, should there be a support statement on M at all, or just individual statements?

If we are to represent mixins at all, then I like the idea of making those entries specially, and also marking the interfaces which should include them. Note that there's also https://github.com/mdn/browser-compat-data/issues/3441, about doing something similar for inheritance.

I'd still prefer a statement on M, as it will be more consistent and will also ease automation on TSJS-lib-generator.

Another question: How to indicate some mixin support statements are overridden by interfaces?

My answer: api.WindowOrWorkerGlobalScope.__included = ["Window", ...] and track each item.

@saschanaz what do you think the rule (or lint) for the support statement on M should be? I see two options, with different drawbacks:

  • Supported if on any of the concrete interfaces. This will lead to a lot of support statements for mixins being older than the concept of mixins itself. Harmless?
  • Supported if on all of the concrete interfaces. This will require changing the mixin statement if a new interfaces begins including it, as has just happened with some MathML stuff. This seems harder to maintain over time.

In TSJS perspective I prefer the first option, as it will use the mixin if there is any real implementation. It could be painful for large mixins like GlobalEventHandlers but I guess it should generally be fine as AFAIK many mixins only have one single concrete implementor interface.

In https://github.com/mdn/browser-compat-data/pull/7179#discussion_r515904381 we discovered that there are mismatches between BCD and MDN, where BCD has an api.HTMLElement.style entry which links to https://developer.mozilla.org/en-US/docs/Web/API/ElementCSSInlineStyle/style, and that page in turn includes the data from api.HTMLElement.style.

Since https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style redirects I gather it was renamed at some point.

This sort of thing is bound to come up more when trying to sort everything out.

Now I think I'm more for removing mixins. That way:

  • mdn-bcd-collector doesn't need to care about mixins
  • No complex algorithm needed to create a support table
  • Contributors won't be confused

I still can write code for my use case to track mixin items in BCD, so nothing will be lost.

I just came across something I hadn't seen before and which will also need cleaning up. CharacterData.json has an api.CharacterData.ChildNode entry with the description "Implements the ChildNode interface". It came from wiki migration in https://github.com/mdn/browser-compat-data/pull/1732 and it looks like it's the only case like this.

Alright, so there's some interface history with some SVG interfaces that can make this a little bit more complicated. While I was updating data for some mixins, I discovered that a few of the mixins in SVG were initially their own interfaces in SVG 1.1, but then converted to mixins in SVG 2.0. What should we do in this case?

Related PRs: #8235 and #8201

I filed https://github.com/mdn/browser-compat-data/issues/7752 for the SVG interfaces which were turned into mixins. I think we should treat the ones which are now mixins like all other mixins, however that ends up being. SVGUnitTypes is not a case of this, since it still exists to hold the constants.

(Sidebar re "Contributors won't be confused": I'm more concerned with whether readers and data consumer are confused. I've always believed it's my job as a documentation person to resolve confusion for myself so that readers, hopefully, never will be.

No complex algorithm needed to create a support table

I wonder the support table should ultimately support inheritances, in that case the algorithm is needed anyway.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ddbeck picture ddbeck  Â·  3Comments

ExE-Boss picture ExE-Boss  Â·  3Comments

Krinkle picture Krinkle  Â·  4Comments

ExE-Boss picture ExE-Boss  Â·  3Comments

jwhitlock picture jwhitlock  Â·  4Comments