Web IDL

Living Standard — Last Updated

Participate:
GitHub whatwg/webidl (new issue, open issues)
Chat on Matrix
Commits:
GitHub whatwg/webidl/commits
Snapshot as of this commit
@webidl
Tests:
web-platform-tests webidl/ (ongoing work)
Translations (non-normative):
日本語
简体中文
한국어

Abstract

This standard defines an interface definition language, Web IDL, that can be used to describe interfaces that are intended to be implemented in web browsers.

1. Introduction

This section is informative.

This standard defines an interface definition language, Web IDL, that can be used to describe interfaces that are intended to be implemented in web browsers. Web IDL is an IDL variant with a number of features that allow the behavior of common script objects in the web platform to be specified more readily. How interfaces described with Web IDL correspond to constructs within JavaScript execution environments is also detailed here.

Concretely, Web IDL provides a syntax for specifying the surface APIs of web platform objects, as well as JavaScript bindings that detail how those APIs manifest as JavaScript constructs. This ensures common tasks, such as installing global properties, processing numeric inputs, or exposing iteration behavior, remain uniform across web platform specifications: such specifications describe their interfaces using Web IDL, and then use prose to specify API-specific details.

The term "JavaScript" is used to refer to ECMA-262, rather than the official term ECMAScript, since the term JavaScript is more widely known.

2. Interface definition language

This section describes a language, Web IDL, which can be used to define interfaces for APIs in the Web platform. A specification that defines Web APIs can include one or more IDL fragments that describe the interfaces (the state and behavior that objects can exhibit) for the APIs defined by that specification. An IDL fragment is a sequence of definitions that matches the Definitions grammar symbol. The set of IDL fragments that an implementation supports is not ordered. See IDL grammar for the complete grammar and an explanation of the notation used.

The different kinds of definitions that can appear in an IDL fragment are: interfaces, partial interface definitions, interface mixins, partial mixin definitions, callback functions, callback interfaces, namespaces, partial namespace definitions, dictionaries, partial dictionary definitions, typedefs and includes statements. These are all defined in the following sections.

Each definition (matching Definition) can be preceded by a list of extended attributes (matching ExtendedAttributeList), which can control how the definition will be handled in language bindings. The extended attributes defined by this specification that are language binding agnostic are discussed in § 2.14 Extended attributes, while those specific to the JavaScript language binding are discussed in § 3.3 Extended attributes.

[extended_attributes]
interface identifier {
  /* interface_members... */
};
Definitions ::
    ExtendedAttributeList Definition Definitions
    ε
Definition ::
    CallbackOrInterfaceOrMixin
    Namespace
    Partial
    Dictionary
    Enum
    Typedef
    IncludesStatement

The following is an example of an IDL fragment.

[Exposed=Window]
interface Paint { };

[Exposed=Window]
interface SolidColor : Paint {
  attribute double red;
  attribute double green;
  attribute double blue;
};

[Exposed=Window]
interface Pattern : Paint {
  attribute DOMString imageURL;
};

[Exposed=Window]
interface GraphicalWindow {
  constructor();
  readonly attribute unsigned long width;
  readonly attribute unsigned long height;

  attribute Paint currentPaint;

  undefined drawRectangle(double x, double y, double width, double height);

  undefined drawText(double x, double y, DOMString text);
};

Here, four interfaces are being defined. The GraphicalWindow interface has two read only attributes, one writable attribute, and two operations defined on it. Objects that implement the GraphicalWindow interface will expose these attributes and operations in a manner appropriate to the particular language being used.

In JavaScript, the attributes on the IDL interfaces will be exposed as accessor properties and the operations as data properties whose value is a built-in function object on a prototype object for all GraphicalWindow objects; each JavaScript object that implements GraphicalWindow will have that prototype object in its prototype chain.

The constructor operation that appears on GraphicalWindow causes a constructor to exist in JavaScript implementations, so that calling new GraphicalWindow() would return a new object that implemented the interface.

All interfaces have the [Exposed] extended attribute, which ensures the interfaces are only available in realms whose global object is a Window object.

2.1. Names

Every interface, partial interface definition, namespace, partial namespace definition, dictionary, partial dictionary definition, enumeration, callback function, callback interface and typedef (together called named definitions) and every constant, attribute, and dictionary member has an identifier, as do some operations. The identifier is determined by an identifier token somewhere in the declaration:

Note: Operations can have no identifier when they are being used to declare a special kind of operation, such as a getter or setter.

For all of these constructs, the identifier is the value of the identifier token with any leading U+005F (_) removed.

Note: A leading U+005F (_) is used to escape an identifier from looking like a reserved word so that, for example, an interface named "interface" can be defined. The leading U+005F (_) is dropped to unescape the identifier.

Operation arguments can take a slightly wider set of identifiers. In an operation declaration, the identifier of an argument is specified immediately after its type and is given by either an identifier token or by one of the keywords that match the ArgumentNameKeyword symbol. If one of these keywords is used, it need not be escaped with a leading underscore.

interface interface_identifier {
  return_type operation_identifier(argument_type argument_identifier /* , ... */);
};
ArgumentNameKeyword ::
    attribute
    callback
    const
    constructor
    deleter
    dictionary
    enum
    getter
    includes
    inherit
    interface
    iterable
    maplike
    mixin
    namespace
    partial
    readonly
    required
    setlike
    setter
    static
    stringifier
    typedef
    unrestricted

If an identifier token is used, then the identifier of the operation argument is the value of that token with any leading U+005F (_) removed. If instead one of the ArgumentNameKeyword keyword token is used, then the identifier of the operation argument is simply that token.

The identifier of any of the abovementioned IDL constructs (except operation arguments) must not be "constructor", "toString", or begin with a U+005F (_). These are known as reserved identifiers.

Although the "toJSON" identifier is not a reserved identifier, it must only be used for regular operations that convert objects to JSON types, as described in § 2.5.3.1 toJSON.

Note: Further restrictions on identifier names for particular constructs can be made in later sections.

Within the set of IDL fragments that a given implementation supports, the identifier of every interface, namespace, dictionary, enumeration, callback function, callback interface and typedef must not be the same as the identifier of any other interface, namespace, dictionary, enumeration, callback function, callback interface or typedef.

Within an IDL fragment, a reference to a definition need not appear after the declaration of the referenced definition. References can also be made across IDL fragments.

Therefore, the following IDL fragment is valid:

[Exposed=Window]
interface B : A {
  undefined f(SequenceOfLongs x);
};

[Exposed=Window]
interface A {
};

typedef sequence<long> SequenceOfLongs;

The following IDL fragment demonstrates how identifiers are given to definitions and interface members.

// Typedef identifier: "number"
typedef double number;

// Interface identifier: "System"
[Exposed=Window]
interface System {

  // Operation identifier:          "createObject"
  // Operation argument identifier: "interface"
  object createObject(DOMString _interface);

  // Operation argument identifier: "interface"
  sequence<object> getObjects(DOMString interface);

  // Operation has no identifier; it declares a getter.
  getter DOMString (DOMString keyName);
};

// Interface identifier: "TextField"
[Exposed=Window]
interface TextField {

  // Attribute identifier: "const"
  attribute boolean _const;

  // Attribute identifier: "value"
  attribute DOMString? _value;
};

Note that while the second attribute on the TextField interface need not have been escaped with an underscore (because "value" is not a keyword in the IDL grammar), it is still unescaped to obtain the attribute’s identifier.

2.2. Interfaces

IDL fragments are used to describe object oriented systems. In such systems, objects are entities that have identity and which are encapsulations of state and behavior. An interface is a definition (matching interface InterfaceRest) that declares some state and behavior that an object implementing that interface will expose.

[extended_attributes]
interface identifier {
  /* interface_members... */
};

An interface is a specification of a set of interface members (matching InterfaceMembers). These are the members that appear between the braces in the interface declaration.

Interfaces in Web IDL describe how objects that implement the interface behave. In bindings for object oriented languages, it is expected that an object that implements a particular IDL interface provides ways to inspect and modify the object’s state and to invoke the behavior described by the interface.

An interface can be defined to inherit from another interface. If the identifier of the interface is followed by a U+003A (:) and an identifier, then that identifier identifies the inherited interface. An object that implements an interface that inherits from another also implements that inherited interface. The object therefore will also have members that correspond to the interface members from the inherited interface.

interface identifier : identifier_of_inherited_interface {
  /* interface_members... */
};

The order that members appear in has significance for property enumeration in the JavaScript binding.

Interfaces may specify an interface member that has the same name as one from an inherited interface. Objects that implement the derived interface will expose the member on the derived interface. It is language binding specific whether the overridden member can be accessed on the object.

Consider the following two interfaces.

[Exposed=Window]
interface A {
  undefined f();
  undefined g();
};

[Exposed=Window]
interface B : A {
  undefined f();
  undefined g(DOMString x);
};

In the JavaScript language binding, an instance of B will have a prototype chain that looks like the following:

[Object.prototype: the Object prototype object]
     ↑
[A.prototype: interface prototype object for A]
     ↑
[B.prototype: interface prototype object for B]
     ↑
[instanceOfB]

Calling instanceOfB.f() in JavaScript will invoke the f defined on B. However, the f from A can still be invoked on an object that implements B by calling A.prototype.f.call(instanceOfB).

The inherited interfaces of a given interface A is the set of all interfaces that A inherits from, directly or indirectly. If A does not inherit from another interface, then the set is empty. Otherwise, the set includes the interface B that A inherits from and all of B’s inherited interfaces.

An interface must not be declared such that its inheritance hierarchy has a cycle. That is, an interface A cannot inherit from itself, nor can it inherit from another interface B that inherits from A, and so on.

The list of inclusive inherited interfaces of an interface I is defined as follows:
  1. Let result be « ».

  2. Let interface be I.

  3. While interface is not null:

    1. Append interface to result.

    2. Set interface to the interface that I inherits from, if any, and null otherwise.

  4. Return result.

Note that general multiple inheritance of interfaces is not supported, and objects also cannot implement arbitrary sets of interfaces. Objects can be defined to implement a single given interface A, which means that it also implements all of A’s inherited interfaces. In addition, an includes statement can be used to define that objects implementing an interface A will always also include the members of the interface mixins A includes.

Each interface member can be preceded by a list of extended attributes (matching ExtendedAttributeList), which can control how the interface member will be handled in language bindings.

[extended_attributes]
interface identifier {

  [extended_attributes]
  const type constant_identifier = 42;

  [extended_attributes]
  attribute type identifier;

  [extended_attributes]
  return_type identifier(/* arguments... */);
};

The IDL for interfaces can be split into multiple parts by using partial interface definitions (matching partial interface PartialInterfaceRest). The identifier of a partial interface definition must be the same as the identifier of an interface definition. All of the members that appear on each of the partial interfaces are considered to be members of the interface itself.

interface SomeInterface {
  /* interface_members... */
};

partial interface SomeInterface {
  /* interface_members... */
};

Note: Partial interface definitions are intended for use as a specification editorial aide, allowing the definition of an interface to be separated over more than one section of the document, and sometimes multiple documents.

The order of appearance of an interface definition and any of its partial interface definitions does not matter.

Note: A partial interface definition cannot specify that the interface inherits from another interface. Inheritance is to be specified on the original interface definition.

The relevant language binding determines how interfaces correspond to constructs in the language.

The following extended attributes are applicable to interfaces: [CrossOriginIsolated], [Exposed], [Global], [LegacyFactoryFunction], [LegacyNoInterfaceObject], [LegacyOverrideBuiltIns], [LegacyWindowAlias], and [SecureContext].

The following extended attributes are applicable to partial interfaces: [CrossOriginIsolated], [Exposed], [LegacyOverrideBuiltIns], and [SecureContext].

Interfaces must be annotated with an [Exposed] extended attribute.

The qualified name of an interface interface is defined as follows:

  1. Let identifier be the identifier of interface.

  2. If interface has a [LegacyNamespace] extended attribute, then:

    1. Let namespace be the identifier argument of the [LegacyNamespace] extended attribute.

    2. Return the concatenation of « namespace, identifier » with separator U+002E (.).

  3. Return identifier.

CallbackOrInterfaceOrMixin ::
    callback CallbackRestOrInterface
    interface InterfaceOrMixin
InterfaceOrMixin ::
    InterfaceRest
    MixinRest
InterfaceRest ::
    identifier Inheritance { InterfaceMembers } ;
Partial ::
    partial PartialDefinition
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
PartialInterfaceOrPartialMixin ::
    PartialInterfaceRest
    MixinRest
PartialInterfaceRest ::
    identifier { PartialInterfaceMembers } ;
InterfaceMembers ::
    ExtendedAttributeList InterfaceMember InterfaceMembers
    ε
InterfaceMember ::
    PartialInterfaceMember
    Constructor
PartialInterfaceMembers ::
    ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers
    ε
PartialInterfaceMember ::
    Const
    Operation
    Stringifier
    StaticMember
    Iterable
    AsyncIterable
    ReadOnlyMember
    ReadWriteAttribute
    ReadWriteMaplike
    ReadWriteSetlike
    InheritAttribute
Inheritance ::
    : identifier
    ε

The following IDL fragment demonstrates the definition of two mutually referential interfaces. Both Human and Dog inherit from Animal. Objects that implement either of those two interfaces will thus have a name attribute.

[Exposed=Window]
interface Animal {
  attribute DOMString name;
};

[Exposed=Window]
interface Human : Animal {
  attribute Dog? pet;
};

[Exposed=Window]
interface Dog : Animal {
  attribute Human? owner;
};

The following IDL fragment defines simplified versions of a DOM interfaces and a callback interface.

[Exposed=Window]
interface Node {
  readonly attribute DOMString nodeName;
  readonly attribute Node? parentNode;
  Node appendChild(Node newChild);
  undefined addEventListener(DOMString type, EventListener listener);
};

callback interface EventListener {
  undefined handleEvent(Event event);
};

Plain objects can implement a callback interface like EventListener:

var node = getNode();                                // Obtain an instance of Node.

var listener = {
  handleEvent: function(event) {
    // ...
  }
};
node.addEventListener("click", listener);            // This works.

node.addEventListener("click", function() { ... });  // As does this.

It is not possible for such an object to implement an interface like Node, however:

var node = getNode();  // Obtain an instance of Node.

var newNode = {
  nodeName: "span",
  parentNode: null,
  appendChild: function(newchild) {
    // ...
  },
  addEventListener: function(type, listener) {
    // ...
  }
};
node.appendChild(newNode);  // This will throw a TypeError exception.

2.3. Interface mixins

An interface mixin is a definition (matching interface MixinRest) that declares state and behavior that can be included by one or more interfaces, and that are exposed by objects that implement an interface that includes the interface mixin.

interface mixin identifier {
  /* mixin_members... */
};

Note: Interface mixins, much like partial interfaces, are intended for use as a specification editorial aide, allowing a coherent set of functionalities to be grouped together, and included in multiple interfaces, possibly across documents. They are not meant to be exposed through language bindings. Guidance on when to choose partial interfaces, interface mixins, or partial interface mixins can be found in § 2.3.1 Using mixins and partials.

An interface mixin is a specification of a set of interface mixin members (matching MixinMembers), which are the constants, regular operations, regular attributes, and stringifiers that appear between the braces in the interface mixin declaration.

These constants, regular operations, regular attributes, and stringifiers describe the behaviors that can be implemented by an object, as if they were specified on the interface that includes them.

Static attributes, static operations, special operations, and iterable, asynchronously iterable, maplike, and setlike declarations cannot appear in interface mixin declarations.

As with interfaces, the IDL for interface mixins can be split into multiple parts by using partial interface mixin definitions (matching partial interface MixinRest). The identifier of a partial interface mixin definition must be the same as the identifier of an interface mixin definition. All of the members that appear on each of the partial interface mixin definitions are considered to be members of the interface mixin itself, and—by extension—of the interfaces that include the interface mixin.

interface mixin SomeMixin {
  /* mixin_members... */
};

partial interface mixin SomeMixin {
  /* mixin_members... */
};

The order that members appear in has significance for property enumeration in the JavaScript binding.

Note that unlike interfaces or dictionaries, interface mixins do not create types.

Of the extended attributes defined in this specification, only the [CrossOriginIsolated], [Exposed], and [SecureContext] extended attributes are applicable to interface mixins.

An includes statement is a definition (matching IncludesStatement) used to declare that all objects implementing an interface I (identified by the first identifier) must additionally include the members of interface mixin M (identified by the second identifier). Interface I is said to include interface mixin M.

interface_identifier includes mixin_identifier;

The first identifier must reference a interface I. The second identifier must reference an interface mixin M.

Each member of M is considered to be a member of each interface I, J, K, … that includes M, as if a copy of each member had been made. So for a given member m of M, interface I is considered to have a member mI, interface J is considered to have a member mJ, interface K is considered to have a member mK, and so on. The host interfaces of mI, mJ, and mK, are I, J, and K respectively.

Note: In JavaScript, this implies that each regular operation declared as a member of interface mixin M, and exposed as a data property with a built-in function object value, is a distinct built-in function object in each interface prototype object whose associated interface includes M. Similarly, for attributes, each copy of the accessor property has distinct built-in function objects for its getters and setters.

The order of appearance of includes statements affects the order in which interface mixin are included by their host interface.

Member order isn’t clearly specified, in particular when interface mixins are defined in separate documents. It is discussed in issue #432.

No extended attributes defined in this specification are applicable to includes statements.

The following IDL fragment defines an interface, Entry, and an interface mixin, Observable. The includes statement specifies that Observable’s members are always included on objects implementing Entry.

interface Entry {
  readonly attribute unsigned short entryType;
  // ...
};

interface mixin Observable {
  undefined addEventListener(DOMString type,
                        EventListener listener,
                        boolean useCapture);
  // ...
};

Entry includes Observable;

A JavaScript implementation would thus have an addEventListener property in the prototype chain of every Entry:

var e = getEntry();          // Obtain an instance of Entry.
typeof e.addEventListener;   // Evaluates to "function".
CallbackOrInterfaceOrMixin ::
    callback CallbackRestOrInterface
    interface InterfaceOrMixin
InterfaceOrMixin ::
    InterfaceRest
    MixinRest
Partial ::
    partial PartialDefinition
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
MixinRest ::
    mixin identifier { MixinMembers } ;
MixinMembers ::
    ExtendedAttributeList MixinMember MixinMembers
    ε
MixinMember ::
    Const
    RegularOperation
    Stringifier
    OptionalReadOnly AttributeRest
IncludesStatement ::
    identifier includes identifier ;

2.3.1. Using mixins and partials

This section is informative.

Interface mixins allow the sharing of attributes, constants, and operations across multiple interfaces. If you’re only planning to extend a single interface, you might consider using a partial interface instead.

For example, instead of:

interface mixin WindowSessionStorage {
  readonly attribute Storage sessionStorage;
};
Window includes WindowSessionStorage;

do:

partial interface Window {
  readonly attribute Storage sessionStorage;
};

Additionally, you can rely on extending interface mixins exposed by other specifications to target common use cases, such as exposing a set of attributes, constants, or operations across both window and worker contexts.

For example, instead of the common but verbose:

interface mixin GlobalCrypto {
  readonly attribute Crypto crypto;
};

Window includes GlobalCrypto;
WorkerGlobalScope includes GlobalCrypto;

you can extend the WindowOrWorkerGlobalScope interface mixin using a partial interface mixin:

partial interface mixin WindowOrWorkerGlobalScope {
  readonly attribute Crypto crypto;
};

2.4. Callback interfaces

A callback interface is a definition matching callback interface identifier { CallbackInterfaceMembers } ;. It can be implemented by any object, as described in § 2.12 Objects implementing interfaces.

Note: A callback interface is not an interface. The name and syntax are left over from earlier versions of this standard, where these concepts had more in common.

A callback interface is a specification of a set of callback interface members (matching CallbackInterfaceMembers). These are the members that appear between the braces in the interface declaration.

callback interface identifier {
  /* interface_members... */
};

Note: See also the similarly named callback function definition.

Callback interfaces must define exactly one regular operation.

Specification authors should not define callback interfaces unless required to describe the requirements of existing APIs. Instead, a callback function should be used.

The definition of EventListener as a callback interface is an example of an existing API that needs to allow objects with a given property (in this case handleEvent) to be considered to implement the interface. For new APIs, and those for which there are no compatibility concerns, using a callback function will allow only a function object (in the JavaScript language binding).

Callback interfaces which declare constants must be annotated with an [Exposed] extended attribute.

CallbackRestOrInterface ::
    CallbackRest
    interface identifier { CallbackInterfaceMembers } ;
CallbackInterfaceMembers ::
    ExtendedAttributeList CallbackInterfaceMember CallbackInterfaceMembers
    ε
CallbackInterfaceMember ::
    Const
    RegularOperation

2.5. Members

Interfaces, interface mixins, and namespaces are specifications of a set of members (respectively matching InterfaceMembers, MixinMembers, and NamespaceMembers), which are the constants, attributes, operations, and other declarations that appear between the braces of their declarations. Attributes describe the state that an object implementing the interface, interface mixin, or namespace will expose, and operations describe the behaviors that can be invoked on the object. Constants declare named constant values that are exposed as a convenience to users of objects in the system.

When an interface includes an interface mixin, each member of the interface mixin is also considered a member of the interface. In contrast, inherited interface members are not considered members of the interface.

The constructor steps, getter steps, setter steps, and method steps for the various members defined on an interface or interface mixin have access to a this value, which is an IDL value of the interface type that the member is declared on or that includes the interface mixin the member is declared on.

Setter steps also have access to the given value, which is an IDL value of the type the attribute is declared as.

Interfaces, interface mixins, callback interfaces and namespaces each support a different set of members, which are specified in § 2.2 Interfaces, § 2.3 Interface mixins, § 2.4 Callback interfaces, and § 2.6 Namespaces, and summarized in the following informative table:

Interfaces Callback interfaces Interface mixins Namespaces
Constants
Regular attributes Only read only attributes
Static attributes
Regular Operations
Stringifiers
Special Operations
Static Operations
Iterable declarations
Asynchronously iterable declarations
Maplike declarations
Setlike declarations

2.5.1. Constants

A constant is a declaration (matching Const) used to bind a constant value to a name. Constants can appear on interfaces and callback interfaces.

Constants have in the past primarily been used to define named integer codes in the style of an enumeration. The Web platform is moving away from this design pattern in favor of the use of strings. Editors who wish to use this feature are strongly advised to discuss this by filing an issue before proceeding.

const type constant_identifier = 42;

The identifier of a constant must not be the same as the identifier of another interface member or callback interface member defined on the same interface or callback interface. The identifier also must not be "length", "name" or "prototype".

Note: These three names are the names of properties that are defined on the interface object in the JavaScript language binding.

The type of a constant (matching ConstType) must not be any type other than a primitive type. If an identifier is used, it must reference a typedef whose type is a primitive type.

The ConstValue part of a constant declaration gives the value of the constant, which can be one of the two boolean literal tokens (true and false), an integer token, a decimal token, or one of the three special floating point constant values (-Infinity, Infinity and NaN).

Note: These values – in addition to strings and the empty sequence – can also be used to specify the default value of a dictionary member or of an optional argument. Note that strings, the empty sequence [], and the default dictionary {} cannot be used as the value of a constant.

The value of the boolean literal tokens true and false are the IDL boolean values true and false.

The value of an integer token is an integer whose value is determined as follows:

  1. Let S be the sequence of scalar values matched by the integer token.

  2. Let sign be −1 if S begins with U+002D (-), and 1 otherwise.

  3. Let base be the base of the number based on the scalar values that follow the optional leading U+002D (-):

    U+0030 (0), U+0058 (X)
    U+0030 (0), U+0078 (x)

    The base is 16.

    U+0030 (0)

    The base is 8.

    Otherwise

    The base is 10.

  4. Let number be the result of interpreting all remaining scalar values following the optional leading U+002D (-) character and any scalar values indicating the base as an integer specified in base base.

  5. Return sign × number.

The type of an integer token is the same as the type of the constant, dictionary member or optional argument it is being used as the value of. The value of the integer token must not lie outside the valid range of values for its type, as given in § 2.13 Types.

The value of a decimal token is either an IEEE 754 single-precision floating point number or an IEEE 754 double-precision floating point number, depending on the type of the constant, dictionary member or optional argument it is being used as the value for, determined as follows:
  1. Let S be the sequence of scalar values matched by the decimal token.

  2. Let result be the Mathematical Value that would be obtained if S were parsed as a JavaScript NumericLiteral.

  3. If the decimal token is being used as the value for a float or unrestricted float, then the value of the decimal token is the IEEE 754 single-precision floating point number closest to result.

  4. Otherwise, the decimal token is being used as the value for a double or unrestricted double, and the value of the decimal token is the IEEE 754 double-precision floating point number closest to result. [IEEE-754]

The value of a constant value specified as Infinity, -Infinity, or NaN is either an IEEE 754 single-precision floating point number or an IEEE 754 double-precision floating point number, depending on the type of the constant, dictionary member, or optional argument it is being used as the value for:

Type unrestricted float, constant value Infinity

The value is the IEEE 754 single-precision positive infinity value.

Type unrestricted double, constant value Infinity

The value is the IEEE 754 double-precision positive infinity value.

Type unrestricted float, constant value -Infinity

The value is the IEEE 754 single-precision negative infinity value.

Type unrestricted double, constant value -Infinity

The value is the IEEE 754 double-precision negative infinity value.

Type unrestricted float, constant value NaN

The value is the IEEE 754 single-precision NaN value with the bit pattern 0x7fc00000.

Type unrestricted double, constant value NaN

The value is the IEEE 754 double-precision NaN value with the bit pattern 0x7ff8000000000000.

The type of a decimal token is the same as the type of the constant, dictionary member or optional argument it is being used as the value of. The value of the decimal token must not lie outside the valid range of values for its type, as given in § 2.13 Types. Also, Infinity, -Infinity and NaN must not be used as the value of a float or double.

The value of the null token is the special null value that is a member of the nullable types. The type of the null token is the same as the type of the constant, dictionary member or optional argument it is being used as the value of.

If VT is the type of the value assigned to a constant, and DT is the type of the constant, dictionary member or optional argument itself, then these types must be compatible, which is the case if DT and VT are identical, or DT is a nullable type whose inner type is VT.

Constants are not associated with particular instances of the interface or callback interface on which they appear. It is language binding specific whether constants are exposed on instances.

The JavaScript language binding does however allow constants to be accessed through objects implementing the IDL interfaces on which the constants are declared. For example, with the following IDL:

[Exposed=Window]
interface A {
  const short rambaldi = 47;
};

the constant value can be accessed in JavaScript either as A.rambaldi or instanceOfA.rambaldi.

The following extended attributes are applicable to constants: [CrossOriginIsolated], [Exposed], and [SecureContext].

Const ::
    const ConstType identifier = ConstValue ;
ConstValue ::
    BooleanLiteral
    FloatLiteral
    integer
BooleanLiteral ::
    true
    false
FloatLiteral ::
    decimal
    -Infinity
    Infinity
    NaN
ConstType ::
    PrimitiveType
    identifier

The following IDL fragment demonstrates how constants of the above types can be defined.

[Exposed=Window]
interface Util {
  const boolean DEBUG = false;
  const octet LF = 10;
  const unsigned long BIT_MASK = 0x0000fc00;
  const double AVOGADRO = 6.022e23;
};

2.5.2. Attributes

An attribute is an interface member or namespace member (matching inherit AttributeRest, static OptionalReadOnly AttributeRest, stringifier OptionalReadOnly AttributeRest, OptionalReadOnly AttributeRest, or AttributeRest) that is used to declare data fields with a given type and identifier whose value can be retrieved and (in some cases) changed. There are two kinds of attributes:

  1. regular attributes, which are those used to declare that objects implementing the interface will have a data field member with the given identifier

    interface interface_identifier {
      attribute type identifier;
    };
    
  2. static attributes, which are used to declare attributes that are not associated with a particular object implementing the interface

    interface interface_identifier {
      static attribute type identifier;
    };
    

If an attribute has no static keyword, then it declares a regular attribute. Otherwise, it declares a static attribute. Note that in addition to being interface members, read only regular attributes can be namespace members as well.

The getter steps of an attribute attr should be introduced using text of the form “The attr getter steps are:” followed by a list, or “The attr getter steps are to” followed by an inline description.

The setter steps of an attribute attr should be introduced using text of the form “The attr setter steps are:” followed by a list, or “The attr setter steps are to” followed by an inline description.

Note: When defining getter steps, you implicitly have access to this. When defining setter steps, you implicitly have access to this and the given value.

The identifier of an attribute must not be the same as the identifier of another interface member defined on the same interface. The identifier of a static attribute must not be "prototype".

The type of the attribute is given by the type (matching Type) that appears after the attribute keyword. If the Type is an identifier or an identifier followed by ?, then the identifier must identify an interface, enumeration, callback function, callback interface or typedef.

The type of the attribute, after resolving typedefs, must not be a nullable or non-nullable version of any of the following types:

The attribute is read only if the readonly keyword is used before the attribute keyword. An object that implements the interface on which a read only attribute is defined will not allow assignment to that attribute. It is language binding specific whether assignment is simply disallowed by the language, ignored or an exception is thrown.

interface interface_identifier {
  readonly attribute type identifier;
};

Attributes whose type is a promise type must be read only. Additionally, they cannot have any of the extended attributes [LegacyLenientSetter], [PutForwards], [Replaceable], or [SameObject].

A regular attribute that is not read only can be declared to inherit its getter from an ancestor interface. This can be used to make a read only attribute in an ancestor interface be writable on a derived interface. An attribute inherits its getter if its declaration includes inherit in the declaration. The read only attribute from which the attribute inherits its getter is the attribute with the same identifier on the closest ancestor interface of the one on which the inheriting attribute is defined. The attribute whose getter is being inherited must be of the same type as the inheriting attribute.

Note: The grammar ensures that inherit does not appear on a read only attribute or a static attribute.

[Exposed=Window]
interface Ancestor {
  readonly attribute TheType theIdentifier;
};

[Exposed=Window]
interface Derived : Ancestor {
  inherit attribute TheType theIdentifier;
};

When the stringifier keyword is used in a regular attribute declaration, it indicates that objects implementing the interface will be stringified to the value of the attribute. See § 2.5.5 Stringifiers for details.

interface interface_identifier {
  stringifier attribute DOMString identifier;
};

The following extended attributes are applicable to regular and static attributes: [CrossOriginIsolated], [Exposed], [SameObject], and [SecureContext].

The following extended attributes are applicable only to regular attributes: [LegacyLenientSetter], [LegacyLenientThis], [PutForwards], [Replaceable], [LegacyUnforgeable].

ReadOnlyMember ::
    readonly ReadOnlyMemberRest
ReadOnlyMemberRest ::
    AttributeRest
    MaplikeRest
    SetlikeRest
ReadWriteAttribute ::
    AttributeRest
InheritAttribute ::
    inherit AttributeRest
AttributeRest ::
    attribute TypeWithExtendedAttributes AttributeName ;
AttributeName ::
    AttributeNameKeyword
    identifier
AttributeNameKeyword ::
    required
OptionalReadOnly ::
    readonly
    ε

The following IDL fragment demonstrates how attributes can be declared on an interface:

[Exposed=Window]
interface Animal {

  // A simple attribute that can be set to any string value.
  readonly attribute DOMString name;

  // An attribute whose value can be assigned to.
  attribute unsigned short age;
};

[Exposed=Window]
interface Person : Animal {

  // An attribute whose getter behavior is inherited from Animal, and need not be
  // specified in the description of Person.
  inherit attribute DOMString name;
};

2.5.3. Operations

An operation is an interface member, callback interface member or namespace member (matching static RegularOperation, stringifier, RegularOperation or SpecialOperation) that defines a behavior that can be invoked on objects implementing the interface. There are three kinds of operation:

  1. regular operations, which are those used to declare that objects implementing the interface will have a method with the given identifier

    interface interface_identifier {
      return_type identifier(/* arguments... */);
    };
    
  2. special operations, which are used to declare special behavior on objects implementing the interface, such as object indexing and stringification

    interface interface_identifier {
      /* special_keyword */ return_type identifier(/* arguments... */);
      /* special_keyword */ return_type (/* arguments... */);
    };
    
  3. static operations, which are used to declare operations that are not associated with a particular object implementing the interface

    interface interface_identifier {
      static return_type identifier(/* arguments... */);
    };
    

If an operation has an identifier but no static keyword, then it declares a regular operation. If the operation has a special keyword used in its declaration (that is, any keyword matching Special, or the stringifier keyword), then it declares a special operation. A single operation can declare both a regular operation and a special operation; see § 2.5.6 Special operations for details on special operations. Note that in addition to being interface members, regular operations can also be callback interface members and namespace members.

If an operation has no identifier, then it must be declared to be a special operation using one of the special keywords.

The identifier of a regular operation or static operation must not be the same as the identifier of a constant or attribute defined on the same interface, callback interface or namespace. The identifier of a static operation must not be "prototype".

Note: The identifier can be the same as that of another operation on the interface, however. This is how operation overloading is specified.

Note: The identifier of a static operation can be the same as the identifier of a regular operation defined on the same interface.

The return type of the operation is given by the type (matching Type) that appears before the operation’s optional identifier. If the return type is an identifier followed by ?, then the identifier must identify an interface, dictionary, enumeration, callback function, callback interface or typedef.

An operation’s arguments (matching ArgumentList) are given between the parentheses in the declaration. Each individual argument is specified as a type (matching Type) followed by an identifier (matching ArgumentName).

Note: For expressiveness, the identifier of an operation argument can also be specified as one of the keywords matching the ArgumentNameKeyword symbol without needing to escape it.

If the Type of an operation argument is an identifier followed by ?, then the identifier must identify an interface, enumeration, callback function, callback interface, or typedef. If the operation argument type is an identifier not followed by ?, then the identifier must identify any one of those definitions or a dictionary.

If the operation argument type, after resolving typedefs, is a nullable type, its inner type must not be a dictionary type.

interface interface_identifier {
  return_type identifier(type identifier, type identifier /* , ... */);
};

The identifier of each argument must not be the same as the identifier of another argument in the same operation declaration.

Each argument can be preceded by a list of extended attributes (matching ExtendedAttributeList), which can control how a value passed as the argument will be handled in language bindings.

interface interface_identifier {
  return_type identifier([extended_attributes] type identifier, [extended_attributes] type identifier /* , ... */);
};

The following IDL fragment demonstrates how regular operations can be declared on an interface:

[Exposed=Window]
interface Dimensions {
  attribute unsigned long width;
  attribute unsigned long height;
};

[Exposed=Window]
interface Button {

  // An operation that takes no arguments and returns a boolean.
  boolean isMouseOver();

  // Overloaded operations.
  undefined setDimensions(Dimensions size);
  undefined setDimensions(unsigned long width, unsigned long height);
};

An operation or constructor operation is considered to be variadic if the final argument uses the ... token just after the argument type. Declaring an operation to be variadic indicates that the operation can be invoked with any number of arguments after that final argument. Those extra implied formal arguments are of the same type as the final explicit argument in the operation declaration. The final argument can also be omitted when invoking the operation. An argument must not be declared with the ... token unless it is the final argument in the operation’s argument list.

interface interface_identifier {
  return_type identifier(type... identifier);
  return_type identifier(type identifier, type... identifier);
};

Extended attributes that take an argument list ([LegacyFactoryFunction], of those defined in this specification) and callback functions are also considered to be variadic when the ... token is used in their argument lists.

The following IDL fragment defines an interface that has two variadic operations:

[Exposed=Window]
interface IntegerSet {
  readonly attribute unsigned long cardinality;

  undefined union(long... ints);
  undefined intersection(long... ints);
};

In the JavaScript binding, variadic operations are implemented by functions that can accept the subsequent arguments:

var s = getIntegerSet();  // Obtain an instance of IntegerSet.

s.union();                // Passing no arguments corresponding to 'ints'.
s.union(1, 4, 7);         // Passing three arguments corresponding to 'ints'.

A binding for a language that does not support variadic functions might specify that an explicit array or list of integers be passed to such an operation.

An argument is considered to be an optional argument if it is declared with the optional keyword. The final argument of a variadic operation is also considered to be an optional argument. Declaring an argument to be optional indicates that the argument value can be omitted when the operation is invoked. The final argument in an operation must not explicitly be declared to be optional if the operation is variadic.

interface interface_identifier {
  return_type identifier(type identifier, optional type identifier);
};

Optional arguments can also have a default value specified. If the argument’s identifier is followed by a U+003D (=) and a value (matching DefaultValue), then that gives the optional argument its default value. The implicitly optional final argument of a variadic operation must not have a default value specified. The default value is the value to be assumed when the operation is called with the corresponding argument omitted.

interface interface_identifier {
  return_type identifier(type identifier, optional type identifier = "value");
};

It is strongly suggested not to use a default value of true for boolean-typed arguments, as this can be confusing for authors who might otherwise expect the default conversion of undefined to be used (i.e., false). [API-DESIGN-PRINCIPLES]

If the type of an argument is a dictionary type or a union type that has a dictionary type as one of its flattened member types, and that dictionary type and its ancestors have no required members, and the argument is either the final argument or is followed only by optional arguments, then the argument must be specified as optional and have a default value provided.

This is to encourage API designs that do not require authors to pass an empty dictionary value when they wish only to use the dictionary’s default values.

Usually the default value provided will be {}, but in the case of a union type that has a dictionary type as one of its flattened member types a default value could be provided that initializes some other member of the union.

When a boolean literal token (true or false), the null token, an integer token, a decimal token or one of the three special floating point literal values (Infinity, -Infinity or NaN) is used as the default value, it is interpreted in the same way as for a constant.

When the undefined token is used as the default value, the value is the IDL undefined value.

Optional argument default values can also be specified using a string token, whose value is a string type determined as follows:
  1. Let S be the sequence of scalar values matched by the string token with its leading and trailing U+0022 (") scalar values removed.

  2. Depending on the type of the argument:

    DOMString
    USVString
    an enumeration type

    The value of the string token is S.

    ByteString

    Assert: S doesn’t contain any code points higher than U+00FF.

    The value of the string token is the isomorphic encoding of S.

If the type of the optional argument is an enumeration, then its default value if specified must be one of the enumeration’s values.

Optional argument default values can also be specified using the two token value [], which represents an empty sequence value. The type of this value is the same as the type of the optional argument it is being used as the default value of. That type must be a sequence type, a nullable type whose inner type is a sequence type or a union type or nullable union type that has a sequence type in its flattened member types.

Optional argument default values can also be specified using the two token value {}, which represents a default-initialized (as if from ES null or an object with no properties) dictionary value. The type of this value is the same as the type of the optional argument it is being used as the default value of. That type must be a dictionary type, or a union type that has a dictionary type in its flattened member types.

The following IDL fragment defines an interface with a single operation that can be invoked with two different argument list lengths:

[Exposed=Window]
interface ColorCreator {
  object createColor(double v1, double v2, double v3, optional double alpha);
};

It is equivalent to an interface that has two overloaded operations:

[Exposed=Window]
interface ColorCreator {
  object createColor(double v1, double v2, double v3);
  object createColor(double v1, double v2, double v3, double alpha);
};

The following IDL fragment defines an interface with an operation that takes a dictionary argument:

dictionary LookupOptions {
  boolean caseSensitive = false;
};

[Exposed=Window]
interface AddressBook {
  boolean hasAddressForName(USVString name, optional LookupOptions options = {});
};

If hasAddressForName is called with only one argument, the second argument will be a default-initialized LookupOptions dictionary, which will cause caseSensitive to be set to false.

The following extended attributes are applicable to operations: [CrossOriginIsolated], [Default], [Exposed], [LegacyUnforgeable], [NewObject], and [SecureContext].

The method steps of an operation operation should be introduced using text of the form “The operation(arg1, arg2, ...) method steps are:” followed by a list, or “The operation(arg1, arg2, ...) method steps are to” followed by an inline description.

Note: When defining method steps, you implicitly have access to this.

DefaultValue ::
    ConstValue
    string
    [ ]
    { }
    null
    undefined
Operation ::
    RegularOperation
    SpecialOperation
RegularOperation ::
    Type OperationRest
SpecialOperation ::
    Special RegularOperation
Special ::
    getter
    setter
    deleter
OperationRest ::
    OptionalOperationName ( ArgumentList ) ;
OptionalOperationName ::
    OperationName
    ε
OperationName ::
    OperationNameKeyword
    identifier
OperationNameKeyword ::
    includes
ArgumentList ::
    Argument Arguments
    ε
Arguments ::
    , Argument Arguments
    ε
Argument ::
    ExtendedAttributeList ArgumentRest
ArgumentRest ::
    optional TypeWithExtendedAttributes ArgumentName Default
    Type Ellipsis ArgumentName
ArgumentName ::
    ArgumentNameKeyword
    identifier
Ellipsis ::
    ...
    ε
ArgumentNameKeyword ::
    attribute
    callback
    const
    constructor
    deleter
    dictionary
    enum
    getter
    includes
    inherit
    interface
    iterable
    maplike
    mixin
    namespace
    partial
    readonly
    required
    setlike
    setter
    static
    stringifier
    typedef
    unrestricted
2.5.3.1. toJSON

By declaring a toJSON regular operation, an interface specifies how to convert the objects that implement it to JSON types.

The toJSON regular operation is reserved for this usage. It must take zero arguments and return a JSON type.

The JSON types are:

How the toJSON regular operation is made available on an object in a language binding, and how exactly the JSON types are converted into a JSON string, is language binding specific.

Note: In the JavaScript language binding, this is done by exposing a toJSON method which returns the JSON type converted into a JavaScript value that can be turned into a JSON string by the JSON.stringify() function. Additionally, in the JavaScript language binding, the toJSON operation can take a [Default] extended attribute, in which case the default toJSON steps are exposed instead.

The following IDL fragment defines an interface Transaction that has a toJSON method defined in prose:

[Exposed=Window]
interface Transaction {
  readonly attribute DOMString from;
  readonly attribute DOMString to;
  readonly attribute double amount;
  readonly attribute DOMString description;
  readonly attribute unsigned long number;
  TransactionJSON toJSON();
};

dictionary TransactionJSON {
  Account from;
  Account to;
  double amount;
  DOMString description;
};

The toJSON regular operation of Transaction interface could be defined as follows:

The toJSON() method steps are:

  1. Let json be a new map.

  2. For each attribute identifier attr in « "from", "to", "amount", "description" »:

    1. Let value be the result of running the getter steps of attr on this.

    2. Set json[attr] to value.

  3. Return json.

In the JavaScript language binding, there would exist a toJSON() method on Transaction objects:

// Get an instance of Transaction.
var txn = getTransaction();

// Evaluates to an object like this:
// {
//   from: "Bob",
//   to: "Alice",
//   amount: 50,
//   description: "books"
// }
txn.toJSON();

// Evaluates to a string like this:
// '{"from":"Bob","to":"Alice","amount":50,"description":"books"}'
JSON.stringify(txn);

2.5.4. Constructor operations

If an interface has a constructor operation member (matching Constructor), it indicates that it is possible to create objects that implement the interface using a constructor.

Multiple constructor operations may appear on a given interface. For each constructor operation on the interface, there will be a way to attempt to construct an instance by passing the specified arguments.

The constructor steps of a constructor operation that is a member of an interface named interface should be introduced using text of the form “The new interface(arg1, arg2, ...) constructor steps are:” followed by a list, or “The new interface(arg1, arg2, ...) constructor steps are to” followed by an inline description.

The constructor steps must do nothing, initialize the value passed as this, or throw an exception.

If the constructor does not initialize this, one can write “The new Example(init) constructor steps are to do nothing.”

See § 3.7.1 Interface object for details on how a constructor operation is to be implemented.

The following IDL defines two interfaces. The second has constructor operations, while the first does not.

[Exposed=Window]
interface NodeList {
  Node item(unsigned long index);
  readonly attribute unsigned long length;
};

[Exposed=Window]
interface Circle {
  constructor();
  constructor(double radius);
  attribute double r;
  attribute double cx;
  attribute double cy;
  readonly attribute double circumference;
};

A JavaScript implementation supporting these interfaces would implement a [[Construct]] internal method on the Circle interface object which would return a new object that implements the interface. It would take either zero or one argument.

It is unclear whether the NodeList interface object would implement a [[Construct]] internal method. In any case, trying to use it as a constructor will cause a TypeError to be thrown. [whatwg/webidl Issue #698]

var x = new Circle();      // This uses the zero-argument constructor to create a
                           // reference to a platform object that implements the
                           // Circle interface.

var y = new Circle(1.25);  // This also creates a Circle object, this time using
                           // the one-argument constructor.

var z = new NodeList();    // This would throw a TypeError, since no
                           // constructor is declared.
Constructor ::
    constructor ( ArgumentList ) ;
ArgumentList ::
    Argument Arguments
    ε
Arguments ::
    , Argument Arguments
    ε
Argument ::
    ExtendedAttributeList ArgumentRest
ArgumentRest ::
    optional TypeWithExtendedAttributes ArgumentName Default
    Type Ellipsis ArgumentName
ArgumentName ::
    ArgumentNameKeyword
    identifier
Ellipsis ::
    ...
    ε
ArgumentNameKeyword ::
    attribute
    callback
    const
    constructor
    deleter
    dictionary
    enum
    getter
    includes
    inherit
    interface
    iterable
    maplike
    mixin
    namespace
    partial
    readonly
    required
    setlike
    setter
    static
    stringifier
    typedef
    unrestricted

2.5.5. Stringifiers

When an interface has a stringifier, it indicates that objects that implement the interface have a non-default conversion to a string. Stringifiers can be specified using a stringifier keyword, which creates a stringifier operation when used alone.

interface interface_identifier {
  stringifier;
};

Prose accompanying the interface must define the stringification behavior of the interface.

The stringifier keyword can also be placed on an attribute. In this case, the string to convert the object to is the value of the attribute. The stringifier keyword must not be placed on an attribute unless it is declared to be of type DOMString or USVString. It also must not be placed on a static attribute.

interface interface_identifier {
  stringifier attribute DOMString identifier;
};

On a given interface, there must exist at most one stringifier.

Stringifier ::
    stringifier StringifierRest
StringifierRest ::
    OptionalReadOnly AttributeRest
    ;

The following IDL fragment defines an interface that will stringify to the value of its name attribute:

[Exposed=Window]
interface Student {
  constructor();
  attribute unsigned long id;
  stringifier attribute DOMString name;
};

In the JavaScript binding, using a Student object in a context where a string is expected will result in the value of the object’s name property being used:

var s = new Student();
s.id = 12345678;
s.name = '周杰倫';

var greeting = 'Hello, ' + s + '!';  // Now greeting == 'Hello, 周杰倫!'.

The following IDL fragment defines an interface that has custom stringification behavior that is not specified in the IDL itself.

[Exposed=Window]
interface Student {
  constructor();
  attribute unsigned long id;
  attribute DOMString? familyName;
  attribute DOMString givenName;

  stringifier;
};

Thus, there needs to be prose to explain the stringification behavior. We assume that the familyName and givenName attributes are backed by family name and given name concepts, respectively.

The stringification behavior steps are:

  1. If this’s family name is null, then return this’s given name.

  2. Return the concatenation of this’s given name, followed by U+0020 SPACE, followed by this’s family name.

A JavaScript implementation of the IDL would behave as follows:

var s = new Student();
s.id = 12345679;
s.familyName = 'Smithee';
s.givenName = 'Alan';

var greeting = 'Hi ' + s;  // Now greeting == 'Hi Alan Smithee'.

2.5.6. Special operations

A special operation is a declaration of a certain kind of special behavior on objects implementing the interface on which the special operation declarations appear. Special operations are declared by using a special keyword in an operation declaration.

There are three kinds of special operations. The table below indicates for a given kind of special operation what special keyword is used to declare it and what the purpose of the special operation is:

Special operation Keyword Purpose
Getters getter Defines behavior for when an object is indexed for property retrieval.
Setters setter Defines behavior for when an object is indexed for property assignment or creation.
Deleters deleter Defines behavior for when an object is indexed for property deletion.

Not all language bindings support all of the four kinds of special object behavior. When special operations are declared using operations with no identifier, then in language bindings that do not support the particular kind of special operations there simply will not be such functionality.

The following IDL fragment defines an interface with a getter and a setter:

[Exposed=Window]
interface Dictionary {
  readonly attribute unsigned long propertyCount;

  getter double (DOMString propertyName);
  setter undefined (DOMString propertyName, double propertyValue);
};

In language bindings that do not support property getters and setters, objects implementing Dictionary will not have that special behavior.

Defining a special operation with an identifier is equivalent to separating the special operation out into its own declaration without an identifier. This approach is allowed to simplify method steps of an interface’s operations.

The following two interfaces are equivalent:

[Exposed=Window]
interface Dictionary {
  readonly attribute unsigned long propertyCount;

  getter double getProperty(DOMString propertyName);
  setter undefined setProperty(DOMString propertyName, double propertyValue);
};
[Exposed=Window]
interface Dictionary {
  readonly attribute unsigned long propertyCount;

  double getProperty(DOMString propertyName);
  undefined setProperty(DOMString propertyName, double propertyValue);

  getter double (DOMString propertyName);
  setter undefined (DOMString propertyName, double propertyValue);
};

A given special keyword must not appear twice on an operation.

Getters and setters come in two varieties: ones that take a DOMString as a property name, known as named property getters and named property setters, and ones that take an unsigned long as a property index, known as indexed property getters and indexed property setters. There is only one variety of deleter: named property deleters. See § 2.5.6.1 Indexed properties and § 2.5.6.2 Named properties for details.

On a given interface, there must exist at most one named property deleter, and at most one of each variety of getter and setter.

If an interface has a setter of a given variety, then it must also have a getter of that variety. If it has a named property deleter, then it must also have a named property getter.

Special operations declared using operations must not be variadic nor have any optional arguments.

If an object implements more than one interface that defines a given special operation, then it is undefined which (if any) special operation is invoked for that operation.

2.5.6.1. Indexed properties

An interface that defines an indexed property getter is said to support indexed properties. By extension, a platform object is said to support indexed properties if it implements an interface that itself does.

If an interface supports indexed properties, then the interface definition must be accompanied by a description of what indices the object can be indexed with at any given time. These indices are called the supported property indices.

Interfaces that support indexed properties must define an integer-typed attribute named "length".

Indexed property getters must be declared to take a single unsigned long argument. Indexed property setters must be declared to take two arguments, where the first is an unsigned long.

interface interface_identifier {
  getter type identifier(unsigned long identifier);
  setter type identifier(unsigned long identifier, type identifier);

  getter type (unsigned long identifier);
  setter type (unsigned long identifier, type identifier);
};

The following requirements apply to the definitions of indexed property getters and setters:

Note that if an indexed property getter or setter is specified using an operation with an identifier, then indexing an object with an integer that is not a supported property index does not necessarily elicit the same behavior as invoking the operation with that index. The actual behavior in this case is language binding specific.

In the JavaScript language binding, a regular property lookup is done. For example, take the following IDL:

[Exposed=Window]
interface A {
  getter DOMString toWord(unsigned long index);
};

Assume that an object implementing A has supported property indices in the range 0 ≤ index < 2. Also assume that toWord is defined to return its argument converted into an English word. The behavior when invoking the operation with an out of range index is different from indexing the object directly:

var a = getA();

a.toWord(0);  // Evalautes to "zero".
a[0];         // Also evaluates to "zero".

a.toWord(5);  // Evaluates to "five".
a[5];         // Evaluates to undefined, since there is no property "5".

The following IDL fragment defines an interface OrderedMap which allows retrieving and setting values by name or by index number:

[Exposed=Window]
interface OrderedMap {
  readonly attribute unsigned long size;

  getter any getByIndex(unsigned long index);
  setter undefined setByIndex(unsigned long index, any value);

  getter any get(DOMString name);
  setter undefined set(DOMString name, any value);
};

Since all of the special operations are declared using operations with identifiers, the only additional prose that is necessary is that which describes what keys those sets have. Assuming that the get() operation is defined to return null if an attempt is made to look up a non-existing entry in the OrderedMap, then the following two sentences would suffice:

An object map implementing OrderedMap supports indexed properties with indices in the range 0 ≤ index < map.size.

Such objects also support a named property for every name that, if passed to get(), would return a non-null value.

As described in § 3.9 Legacy platform objects, a JavaScript implementation would create properties on a legacy platform object implementing OrderedMap that correspond to entries in both the named and indexed property sets. These properties can then be used to interact with the object in the same way as invoking the object’s methods, as demonstrated below:

// Assume map is a legacy platform object implementing the OrderedMap interface.
var map = getOrderedMap();
var x, y;

x = map[0];       // If map.length > 0, then this is equivalent to:
                  //
                  //   x = map.getByIndex(0)
                  //
                  // since a property named "0" will have been placed on map.
                  // Otherwise, x will be set to undefined, since there will be
                  // no property named "0" on map.

map[1] = false;   // This will do the equivalent of:
                  //
                  //   map.setByIndex(1, false)

y = map.apple;    // If there exists a named property named "apple", then this
                  // will be equivalent to:
                  //
                  //   y = map.get('apple')
                  //
                  // since a property named "apple" will have been placed on
                  // map.  Otherwise, y will be set to undefined, since there
                  // will be no property named "apple" on map.

map.berry = 123;  // This will do the equivalent of:
                  //
                  //   map.set('berry', 123)

delete map.cake;  // If a named property named "cake" exists, then the "cake"
                  // property will be deleted, and then the equivalent to the
                  // following will be performed:
                  //
                  //   map.remove("cake")
2.5.6.2. Named properties

An interface that defines a named property getter is said to support named properties. By extension, a platform object is said to support named properties if it implements an interface that itself does.

If an interface supports named properties, then the interface definition must be accompanied by a description of the ordered set of names that can be used to index the object at any given time. These names are called the supported property names.

Named property getters and deleters must be declared to take a single DOMString argument. Named property setters must be declared to take two arguments, where the first is a DOMString.

interface interface_identifier {
  getter type identifier(DOMString identifier);
  setter type identifier(DOMString identifier, type identifier);
  deleter type identifier(DOMString identifier);

  getter type (DOMString identifier);
  setter type (DOMString identifier, type identifier);
  deleter type (DOMString identifier);
};

The following requirements apply to the definitions of named property getters, setters and deleters:

Note: As with indexed properties, if an named property getter, setter or deleter is specified using an operation with an identifier, then indexing an object with a name that is not a supported property name does not necessarily elicit the same behavior as invoking the operation with that name; the behavior is language binding specific.

2.5.7. Static attributes and operations

Static attributes and static operations are ones that are not associated with a particular instance of the interface on which it is declared, and is instead associated with the interface itself. Static attributes and operations are declared by using the static keyword in their declarations.

It is language binding specific whether it is possible to invoke a static operation or get or set a static attribute through a reference to an instance of the interface.

StaticMember ::
    static StaticMemberRest
StaticMemberRest ::
    OptionalReadOnly AttributeRest
    RegularOperation

The following IDL fragment defines an interface Circle that has a static operation declared on it:

[Exposed=Window]
interface Point { /* ... */ };

[Exposed=Window]
interface Circle {
  attribute double cx;
  attribute double cy;
  attribute double radius;

  static readonly attribute long triangulationCount;
  static Point triangulate(Circle c1, Circle c2, Circle c3);
};

In the JavaScript language binding, the function object for triangulate and the accessor property for triangulationCount will exist on the interface object for Circle:

var circles = getCircles();           // an Array of Circle objects

typeof Circle.triangulate;            // Evaluates to "function"
typeof Circle.triangulationCount;     // Evaluates to "number"
Circle.prototype.triangulate;         // Evaluates to undefined
Circle.prototype.triangulationCount;  // Also evaluates to undefined
circles[0].triangulate;               // As does this
circles[0].triangulationCount;        // And this

// Call the static operation
var triangulationPoint = Circle.triangulate(circles[0], circles[1], circles[2]);

// Find out how many triangulations we have done
window.alert(Circle.triangulationCount);

2.5.8. Overloading

If a regular operation or static operation defined on an interface has an identifier that is the same as the identifier of another operation on that interface of the same kind (regular or static), then the operation is said to be overloaded. When the identifier of an overloaded operation is used to invoke one of the operations on an object that implements the interface, the number and types of the arguments passed to the operation determine which of the overloaded operations is actually invoked. Constructor operations can be overloaded too. There are some restrictions on the arguments that overloaded operations and constructors can be specified to take, and in order to describe these restrictions, the notion of an effective overload set is used.

A set of overloaded operations must either:

Operations must not be overloaded across interface, partial interface, interface mixin, and partial interface mixin definitions.

For example, the overloads for both f and g are disallowed:

[Exposed=Window]
interface A {
  undefined f();
};

partial interface A {
  undefined f(double x);
  undefined g();
};

partial interface A {
  undefined g(DOMString x);
};

Note that constructor operations and [LegacyFactoryFunction] extended attributes are disallowed from appearing on partial interface definitions, so there is no need to also disallow overloading for constructors.

An effective overload set represents the allowable invocations for a particular operation, constructor (specified with a constructor operation or [LegacyFactoryFunction]), or callback function. The algorithm to compute the effective overload set operates on one of the following four types of IDL constructs, and listed with them below are the inputs to the algorithm needed to compute the set.

For regular operations
For static operations
For constructors
For legacy factory functions

An effective overload set is used, among other things, to determine whether there are ambiguities in the overloaded operations and constructors specified on an interface.

The items of an effective overload set are tuples of the form (callable, type list, optionality list) whose items are described below:

Each tuple represents an allowable invocation of the operation, constructor, or callback function with an argument value list of the given types. Due to the use of optional arguments and variadic operations and constructors, there may be multiple items in an effective overload set identifying the same operation or constructor.

The algorithm below describes how to compute the effective overload set. The following input variables are used, if they are required:

Whenever an argument of an extended attribute is mentioned, it is referring to an argument of the extended attribute’s named argument list.

  1. Let S be an ordered set.

  2. Let F be an ordered set with items as follows, according to the kind of effective overload set:

    For regular operations

    The elements of F are the regular operations with identifier A defined on interface I.

    For static operations

    The elements of F are the static operations with identifier A defined on interface I.

    For constructors

    The elements of F are the constructor operations on interface I.

    For legacy factory functions

    The elements of F are the [LegacyFactoryFunction] extended attributes on interface I whose named argument lists' identifiers are A.

  3. Let maxarg be the maximum number of arguments the operations, legacy factory functions, or callback functions in F are declared to take. For variadic operations and legacy factory functions, the argument on which the ellipsis appears counts as a single argument.

    Note: So undefined f(long x, long... y); is considered to be declared to take two arguments.

  4. Let max be max(maxarg, N).

  5. For each operation or extended attribute X in F:

    1. Let arguments be the list of arguments X is declared to take.

    2. Let n be the size of arguments.

    3. Let types be a type list.

    4. Let optionalityValues be an optionality list.

    5. For each argument in arguments:

      1. Append the type of argument to types.

      2. Append "variadic" to optionalityValues if argument is a final, variadic argument, "optional" if argument is optional, and "required" otherwise.

    6. Append the tuple (X, types, optionalityValues) to S.

    7. If X is declared to be variadic, then:

      1. For each i in the range n to max − 1, inclusive:

        1. Let t be a type list.

        2. Let o be an optionality list.

        3. For each j in the range 0 to n − 1, inclusive:

          1. Append types[j] to t.

          2. Append optionalityValues[j] to o.

        4. For each j in the range n to i, inclusive:

          1. Append types[n − 1] to t.

          2. Append "variadic" to o.

        5. Append the tuple (X, t, o) to S.

    8. Let i be n − 1.

    9. While i ≥ 0:

      1. If arguments[i] is not optional (i.e., it is not marked as "optional" and is not a final, variadic argument), then break.

      2. Let t be a type list.

      3. Let o be an optionality list.

      4. For each j in the range 0 to i − 1, inclusive:

        1. Append types[j] to t.

        2. Append optionalityValues[j] to o.

      5. Append the tuple (X, t, o) to S.

        Note: if i is 0, this means to add to S the tuple (X, « », « »); (where "« »" represents an empty list).

      6. Set i to i − 1.

  6. Return S.

For the following interface:

[Exposed=Window]
interface A {
  /* f1 */ undefined f(DOMString a);
  /* f2 */ undefined f(Node a, DOMString b, double... c);
  /* f3 */ undefined f();
  /* f4 */ undefined f(Event a, DOMString b, optional DOMString c, double... d);
};

assuming Node and Event are two other interfaces of which no object can implement both, the effective overload set for regular operations with identifier f and argument count 4 is:

«
  (f1, « DOMString »,                           « required »),
  (f2, « Node, DOMString »,                     « required, required »),
  (f2, « Node, DOMString, double »,             « required, required, variadic »),
  (f2, « Node, DOMString, double, double »,     « required, required, variadic, variadic »),
  (f3, « »,                                     « »),
  (f4, « Event, DOMString »,                    « required, required »),
  (f4, « Event, DOMString, DOMString »,         « required, required, optional »),
  (f4, « Event, DOMString, DOMString, double », « required, required, optional, variadic »)
»

Two types are distinguishable if the following algorithm returns true.

  1. If one type includes a nullable type and the other type either includes a nullable type, is a union type with flattened member types including a dictionary type, or is a dictionary type, return false.

    None of the following pairs are distinguishable:
  2. If both types are either a union type or nullable union type, return true if each member type of the one is distinguishable with each member type of the other, or false otherwise.

  3. If one type is a union type or nullable union type, return true if each member type of the union type is distinguishable with the non-union type, or false otherwise.

  4. Consider the two "innermost" types derived by taking each type’s inner type if it is an annotated type, and then taking its inner type inner type if the result is a nullable type. If these two innermost types appear or are in categories appearing in the following table and there is a “●” mark in the corresponding entry or there is a letter in the corresponding entry and the designated additional requirement below the table is satisfied, then return true. Otherwise return false.

    Categories:

    interface-like
    dictionary-like
    sequence-like
    undefined
    boolean
    numeric types
    bigint
    string types
    object
    symbol
    interface-like
    callback function
    dictionary-like
    async sequence
    sequence-like
    undefined
    boolean
    numeric types (b)
    bigint
    string types (d)
    object
    symbol
    interface-like (a)
    callback function (c)
    dictionary-like
    async sequence
    sequence-like
    1. The two identified interface-like types are not the same, and no single platform object implements both interface-like types.

    2. The types are distinguishable, but there is a separate restriction on their use in overloading below. Please also note the advice about using unions of these types.

    3. A callback function that does not have [LegacyTreatNonObjectAsNull] extended attribute is distinguishable from a type in the dictionary-like category.

      For example, when converting an ECMAScript value to union type which includes a callback function and a dictionary-like type, if the value is callable, then it is converted to a callback function. Otherwise, it is converted to a dictionary-like type.
    4. The types are distinguishable, but when converting from an ECMAScript value, a string object is never converted to an async sequence type (even if it has a %Symbol.iterator% method), if a string type is also in the overload set or union.

    double and DOMString are distinguishable because there is a ● at the intersection of numeric types with string types.
    double and long are not distinguishable because they are both numeric types, and there is no ● or letter at the intersection of numeric types with numeric types.
    Given:
    callback interface CBIface {
        undefined handle();
    };
    
    [Exposed=Window]
    interface Iface {
        attribute DOMString attr2;
    };
    
    dictionary Dict {
        DOMString field1;
    };
    

    CBIface is distinguishable from Iface because there’s a ● at the intersection of dictionary-like and interface-like, but it is not distinguishable from Dict because there’s no ● at the intersection of dictionary-like and itself.

    Promise types do not appear in the above table, and as a consequence are not distinguishable with any other type.

If there is more than one item in an effective overload set that has a given type list size, then for those items there must be an index i such that for each pair of items the types at index i are distinguishable. The lowest such index is termed the distinguishing argument index for the items of the effective overload set with the given type list size.

An effective overload set must not contain more than one item with the same type list size, where one item has a bigint argument at the distinguishing argument index and another has a numeric type argument at the distinguishing argument index.

Consider the effective overload set shown in the previous example. There are multiple items in the set with type lists 2, 3 and 4. For each of these type list size, the distinguishing argument index is 0, since Node and Event are distinguishable.

The following use of overloading however is invalid:

[Exposed=Window]
interface B {
  undefined f(DOMString x);
  undefined f(USVString x);
};

since DOMString and USVString are not distinguishable.

In addition, for each index j, where j is less than the distinguishing argument index for a given type list size, the types at index j in all of the items' type lists must be the same, and the optionality values at index j in all of the items' optionality lists must be the same.

The following is invalid:

[Exposed=Window]
interface B {
  /* f1 */ undefined f(DOMString w);
  /* f2 */ undefined f(long w, double x, Node y, Node z);
  /* f3 */ undefined f(double w, double x, DOMString y, Node z);
};

For argument count 4, the effective overload set is:

«
  (f1, « DOMString »,                       « required »),
  (f2, « long, double, Node, Node »,        « required, required, required, required »),
  (f3, « double, double, DOMString, Node », « required, required, required, required »)
»

Looking at items with type list size 4, the distinguishing argument index is 2, since Node and DOMString are distinguishable. However, since the arguments in these two overloads at index 0 are different, the overloading is invalid.

2.5.8.1. Overloading vs. union types

This section is informative.

For specifications defining IDL operations, it might seem that overloads and a combination of union types and optional arguments have some feature overlap.

It is first important to note that overloads have different behaviors than union types or optional arguments, and one cannot be fully defined using the other (unless, of course, additional prose is provided, which can defeat the purpose of the Web IDL type system). For example, consider the stroke() operations defined on the CanvasDrawPath interface [HTML]:

interface CanvasDrawPathExcerpt {
  undefined stroke();
  undefined stroke(Path2D path);
};

Per the JavaScript language binding, calling stroke(undefined) on an object implementing CanvasDrawPathExcerpt would attempt to call the second overload, yielding a TypeError since undefined cannot be converted to a Path2D. However, if the operations were instead defined with optional arguments and merged into one,

interface CanvasDrawPathExcerptOptional {
  undefined stroke(optional Path2D path);
};

the overload resolution algorithm would treat the path argument as missing given the same call stroke(undefined), and not throw any exceptions.

Note: For this particular example, the latter behavior is actually what Web developers would generally expect. If CanvasDrawPath were to be designed today, optional arguments would be used for stroke().

Additionally, there are semantic differences as well. Union types are usually used in the sense that "any of the types would work in about the same way". In contrast, overloaded operations are designed to map well to language features such as C++ overloading, and are usually a better fit for operations with more substantial differences in what they do given arguments of different types. However, in most cases, operations with such substantial differences are best off with different names to avoid confusion for Web developers, since the JavaScript language does not provide language-level overloading. As such, overloads are rarely appropriate for new APIs, instead often appearing in legacy APIs or in specialized circumstances.

That being said, we offer the following recommendations and examples in case of difficulties to determine what Web IDL language feature to use:

When the case fits none of the categories above, it is up to the specification author to choose the style, since it is most likely that either style would sufficiently and conveniently describe the intended behavior. However, the definition and conversion algorithms of union types and optional arguments are simpler to implement and reason about than those of overloads, and usually result in more idiomatic APIs in the JavaScript language binding. Thus, unless any other considerations apply, union types, optional arguments, or both are the default choice.

Specifications are also free to mix and match union types and overloads, if the author finds it appropriate and convenient.

2.5.9. Iterable declarations

An interface can be declared to be iterable by using an iterable declaration (matching Iterable) in the body of the interface.

interface interface_identifier {
  iterable<value_type>;
  iterable<key_type, value_type>;
};

Objects implementing an interface that is declared to be iterable support being iterated over to obtain a sequence of values.

Note: In the JavaScript language binding, an interface that is iterable will have entries, forEach, keys, values, and %Symbol.iterator% properties on its interface prototype object.

If a single type parameter is given, then the interface has a value iterator and provides values of the specified type. If two type parameters are given, then the interface has a pair iterator and provides value pairs with the given types.

A value pair, given a key type and a value type, is a struct with two items:

  1. an item whose name is "key", which is referred to as the value pair’s key, and whose value is an IDL value of the key type;

  2. an item whose name is "value", which is referred to as the value pair’s value, and whose value is an IDL value of the value type.

A value iterator must only be declared on an interface that supports indexed properties. The value-type of the value iterator must be the same as the type returned by the indexed property getter. A value iterator is implicitly defined to iterate over the object’s indexed properties.

A pair iterator must not be declared on an interface that supports indexed properties.

Prose accompanying an interface with a pair iterator must define a list of value pairs for each instance of the interface, which is the list of value pairs to iterate over.

The JavaScript forEach method that is generated for a value iterator invokes its callback like Array.prototype.forEach does, and the forEach method for a pair iterator invokes its callback like Map.prototype.forEach does.

Since value iterators are currently allowed only on interfaces that support indexed properties, it makes sense to use an Array-like forEach method. There could be a need for value iterators (a) on interfaces that do not support indexed properties, or (b) with a forEach method that instead invokes its callback like Set.prototype.forEach (where the key is the same as the value). If you’re creating an API that needs such a forEach method, please file an issue.

Note: This is how array iterator objects work. For interfaces that support indexed properties, the iterator objects returned by entries, keys, values, and %Symbol.iterator% are actual array iterator objects.

Interfaces with an iterable declaration must not have any attributes, constants, or regular operations named "entries", "forEach", "keys", or "values", or have any inherited interfaces that have attributes, constants, or regular operations with these names.

Consider the following interface SessionManager, which allows access to a number of Session objects keyed by username:

[Exposed=Window]
interface SessionManager {
  Session getSessionForUser(DOMString username);

  iterable<DOMString, Session>;
};

[Exposed=Window]
interface Session {
  readonly attribute DOMString username;
  // ...
};

The behavior of the iterator could be defined like so:

The value pairs to iterate over are the list of value pairs with the key being the username and the value being the open Session object on the SessionManager object corresponding to that username, sorted by username.

In the JavaScript language binding, the interface prototype object for the SessionManager interface has a values method that is a function, which, when invoked, returns an iterator object that itself has a next method that returns the next value to be iterated over. It has keys and entries methods that iterate over the usernames of session objects and username/Session object pairs, respectively. It also has a %Symbol.iterator% method that allows a SessionManager to be used in a for..of loop that has the same value as the entries method:

// Get an instance of SessionManager.
// Assume that it has sessions for two users, "anna" and "brian".
var sm = getSessionManager();

typeof SessionManager.prototype.values;            // Evaluates to "function"
var it = sm.values();                              // values() returns an iterator object
String(it);                                        // Evaluates to "[object SessionManager Iterator]"
typeof it.next;                                    // Evaluates to "function"

// This loop will log "anna" and then "brian".
for (;;) {
  let result = it.next();
  if (result.done) {
    break;
  }
  let session = result.value;
  console.log(session.username);
}

// This loop will also log "anna" and then "brian".
for (let username of sm.keys()) {
  console.log(username);
}

// Yet another way of accomplishing the same.
for (let [username, session] of sm) {
  console.log(username);
}

An interface must not have more than one iterable declaration. The inherited interfaces of an interface with an iterable declaration must not also have an iterable declaration. An interface with an iterable declaration and its inherited interfaces must not have a maplike declaration, setlike declaration, or asynchronously iterable declaration.

The following extended attributes are applicable to iterable declarations: [CrossOriginIsolated], [Exposed], and [SecureContext].

Iterable ::
    iterable < TypeWithExtendedAttributes OptionalType > ;
OptionalType ::
    , TypeWithExtendedAttributes
    ε

2.5.10. Asynchronously iterable declarations

An interface can be declared to be asynchronously iterable by using an asynchronously iterable declaration (matching AsyncIterable) in the body of the interface.

interface interface_identifier {
  async_iterable<value_type>;
  async_iterable<value_type>(/* arguments... */);
  async_iterable<key_type, value_type>;
  async_iterable<key_type, value_type>(/* arguments... */);
};

Objects that implement an interface that is declared to be asynchronously iterable support being iterated over asynchronously to obtain a sequence of values.

If a single type parameter is given, then the interface has a value asynchronously iterable declaration and asynchronously provides values of the specified type. If two type parameters are given, then the interface has a pair asynchronously iterable declaration and asynchronously provides value pairs with the given types.

If given, an asynchronously iterable declaration’s arguments (matching ArgumentList) must all be optional arguments.

In the JavaScript language binding, an interface that is asynchronously iterable will have %Symbol.asyncIterator% and values properties on its interface prototype object. If the interface has a pair asynchronously iterable declaration, it will additionally have entries and keys properties. All of these methods can be passed optional arguments, which correspond to the argument list in the asynchronously iterable declaration, and are processed by the asynchronous iterator initialization steps, if any exist.

With this in mind, the requirement that all arguments be optional ensures that, in the JavaScript binding, for-await-of can work directly on instances of the interface, since for-await-of calls the %Symbol.asyncIterator% method with no arguments.

Prose accompanying an interface with an asynchronously iterable declaration must define a get the next iteration result algorithm. This algorithm receives the instance of the interface that is being iterated, as well as the async iterator itself (which can be useful for storing state). It must return a Promise that either rejects, resolves with a special end of iteration value to signal the end of the iteration, or resolves with one of the following:

for value asynchronously iterable declarations:

a value of the type given in the declaration;

for pair asynchronously iterable declarations:

a tuple containing a value of the first type given in the declaration, and a value of the second type given in the declaration.

The prose may also define an asynchronous iterator return algorithm. This algorithm receives the instance of the interface that is being iterated, the async iterator itself, and a single argument value of type any. This algorithm is invoked in the case of premature termination of the async iterator. It must return a Promise; if that promise fulfills, its fulfillment value will be ignored, but if it rejects, that failure will be passed on to users of the async iterator API.

In the JavaScript binding, this algorithm allows customizing the behavior when the async iterator’s return() method is invoked. This most commonly occurs when a break or return statement causes an exit from a for-await-of loop.

We could add a similar hook for throw(). So far there has been no need, but if you are creating an API that needs such capabilities, please file an issue.

The prose may also define asynchronous iterator initialization steps. These receive the instance of the interface being iterated, the newly-created iterator object, and a list of IDL values representing the arguments passed, if any.

Interfaces with an asynchronously iterable declaration must not have any attributes, constants, or regular operations named "entries", "keys", or "values", or have any inherited interfaces that have attributes, constants, or regular operations with these names.

Consider the following interface SessionManager, which allows access to a number of Session objects keyed by username:

[Exposed=Window]
interface SessionManager {
  Session getSessionForUser(DOMString username);

  async_iterable<DOMString, Session>;
};

[Exposed=Window]
interface Session {
  readonly attribute DOMString username;
  // ...
};

The behavior of the iterator could be defined like so:

The asynchronous iterator initialization steps for a SessionManager async iterator iterator are:

  1. Set iterator’s current state to "not yet started".

To get the next iteration result for a SessionManager manager and its async iterator iterator:

  1. Let promise be a new promise.

  2. Let key be the following value, if it exists, or null otherwise:

    If iterator’s current state is "not yet started"

    the smallest username in manager’s open sessions, in lexicographical order

    Otherwise

    the smallest username in manager’s open sessions that is greater than iterator’s current state, in lexicographical order

    Note: iterator’s current state might no longer be present in the open sessions.

  3. If key is null, then:

    1. Resolve promise with end of iteration.

  4. Otherwise:

    1. Let session be the Session object corresponding to key.

    2. Resolve promise with (username, session).

    3. Set iterator’s current state to username.

  5. Return promise.

In the JavaScript language binding, the interface prototype object for the SessionManager interface has a values method that is a function, which, when invoked, returns an asynchronous iterator object that itself has a next method that returns the next value to be iterated over. It has keys and entries methods that iterate over the usernames of session objects and (username, Session) object pairs, respectively. It also has a %Symbol.asyncIterator% method that allows a SessionManager to be used in a for await..of loop that has the same value as the entries method:

// Get an instance of SessionManager.
// Assume that it has sessions for two users, "anna" and "brian".
var sm = getSessionManager();

typeof SessionManager.prototype.values;            // Evaluates to "function"
var it = sm.values();                              // values() returns an iterator object
typeof it.next;                                    // Evaluates to "function"

// This loop will log "anna" and then "brian".
for await (let username of sm.keys()) {
  console.log(username);
}

// Yet another way of accomplishing the same.
for await (let [username, session] of sm) {
  console.log(username);
}

An interface must not have more than one asynchronously iterable declaration. The inherited interfaces of an interface with an asynchronously iterable declaration must not also have an asynchronously iterable declaration. An interface with an asynchronously iterable declaration and its inherited interfaces must not have a maplike declaration, setlike declaration, or iterable declaration.

The following extended attributes are applicable to asynchronously iterable declarations: [CrossOriginIsolated], [Exposed], and [SecureContext].

these extended attributes are not currently taken into account. When they are, the effect will be as you would expect.

AsyncIterable ::
    async_iterable < TypeWithExtendedAttributes OptionalType > OptionalArgumentList ;
OptionalArgumentList ::
    ( ArgumentList )
    ε

2.5.11. Maplike declarations

An interface can be declared to be maplike by using a maplike declaration (matching ReadWriteMaplike or readonly MaplikeRest) in the body of the interface.

interface interface_identifier {
  readonly maplike<key_type, value_type>;
  maplike<key_type, value_type>;
};

Objects implementing an interface that is declared to be maplike represent an ordered map of key–value pairs, initially empty, known as that object’s map entries. The types used for the keys and values are given in the angle brackets of the maplike declaration. Keys are required to be unique.

Specification authors can modify the contents of the map entries, which will automatically be reflected in the contents of the object as observed by JavaScript code.

Maplike interfaces support an API for querying the map entries appropriate for the language binding. If the readonly keyword is not used, then it also supports an API for modifying the map entries.

Note: In the JavaScript language binding, the API for interacting with the map entries is similar to that available on JavaScript Map objects. If the readonly keyword is used, this includes entries, forEach, get, has, keys, values, %Symbol.iterator% methods, and a size getter. For read–write maplikes, it also includes clear, delete, and set methods.

Maplike interfaces must not have any attributes, constants, or regular operations named "entries", "forEach", "get", "has", "keys", "size", or "values", or have any inherited interfaces that have attributes, constants, or regular operations with these names.

Read–write maplike interfaces must not have any attributes or constants named "clear", "delete", or "set", or have any inherited interfaces that have attributes or constants with these names.

Note: Read-write maplike interfaces can have regular operations named "clear", "delete", or "set", which will override the default implementation of those methods (defined in § 3.7.11 Maplike declarations). If such regular operations are defined, they must match the input and output expectations of each method, defined in their default implementation sections.

An interface must not have more than one maplike declaration. The inherited interfaces of a maplike interface must not also have a maplike declaration. A maplike interface and its inherited interfaces must not have an iterable declaration, an asynchronously iterable declaration, a setlike declaration, or an indexed property getter.

ReadOnlyMember ::
    readonly ReadOnlyMemberRest
ReadOnlyMemberRest ::
    AttributeRest
    MaplikeRest
    SetlikeRest
ReadWriteMaplike ::
    MaplikeRest
MaplikeRest ::
    maplike < TypeWithExtendedAttributes , TypeWithExtendedAttributes > ;

No extended attributes defined in this specification are applicable to maplike declarations.

Add example.

2.5.12. Setlike declarations

An interface can be declared to be setlike by using a setlike declaration (matching ReadWriteSetlike or readonly SetlikeRest) in the body of the interface.

interface interface_identifier {
  readonly setlike<type>;
  setlike<type>;
};

Objects implementing an interface that is declared to be setlike represent an ordered set of values, initially empty, known as that object’s set entries. The type of the values is given in the angle brackets of the setlike declaration. Values are required to be unique.

Specification authors can modify the contents of the set entries, which will automatically be reflected in the contents of the object as observed by JavaScript code.

Setlike interfaces support an API for querying the set entries appropriate for the language binding. If the readonly keyword is not used, then it also supports an API for modifying the set entries.

Note: In the JavaScript language binding, the API for interacting with the set entries is similar to that available on JavaScript Set objects. If the readonly keyword is used, this includes entries, forEach, has, keys, values, %Symbol.iterator% methods, and a size getter. For read–write setlikes, it also includes add, clear, and delete methods.

Setlike interfaces must not have any attributes, constants, or regular operations named "entries", "forEach", "has", "keys", "size", or "values", or have any inherited interfaces that have attributes, constants, or regular operations with these names.

Read–write setlike interfaces must not have any attributes or constants named "add", "clear", or "delete", or have any inherited interfaces that have attributes or constants with these names.

Note: Read-write setlike interfaces can have regular operations named "add", "clear", or "delete", which will override the default implementation of those methods (defined in § 3.7.12 Setlike declarations). If such regular operations are defined, they must match the input and output expectations of each method, defined in their default implementation sections.

An interface must not have more than one setlike declaration. The inherited interfaces of a setlike interface must not also have a setlike declaration. A setlike interface and its inherited interfaces must not have an iterable declaration, an asynchronously iterable declaration, a maplike declaration, or an indexed property getter.

ReadOnlyMember ::
    readonly ReadOnlyMemberRest
ReadOnlyMemberRest ::
    AttributeRest
    MaplikeRest
    SetlikeRest
ReadWriteSetlike ::
    SetlikeRest
SetlikeRest ::
    setlike < TypeWithExtendedAttributes > ;

No extended attributes defined in this specification are applicable to setlike declarations.

Add example.

2.6. Namespaces

A namespace is a definition (matching Namespace) that declares a global singleton with associated behaviors.

namespace identifier {
  /* namespace_members... */
};

A namespace is a specification of a set of namespace members (matching NamespaceMembers), which are the regular operations, read only regular attributes, and constants that appear between the braces in the namespace declaration. These operations and attributes describe the behaviors packaged into the namespace.

As with interfaces, the IDL for namespaces can be split into multiple parts by using partial namespace definitions (matching partial Namespace). The identifier of a partial namespace definition must be the same as the identifier of a namespace definition. All of the members that appear on each of the partial namespace definitions are considered to be members of the namespace itself.

namespace SomeNamespace {
  /* namespace_members... */
};

partial namespace SomeNamespace {
  /* namespace_members... */
};

Note: As with partial interface definitions, partial namespace definitions are intended for use as a specification editorial aide, allowing the definition of a namespace to be separated over more than one section of the document, and sometimes multiple documents.

The order that members appear in has significance for property enumeration in the JavaScript binding.

Note that unlike interfaces or dictionaries, namespaces do not create types.

Of the extended attributes defined in this specification, only the [CrossOriginIsolated], [Exposed], and [SecureContext] extended attributes are applicable to namespaces.

Namespaces must be annotated with the [Exposed] extended attribute.

Partial ::
    partial PartialDefinition
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
Namespace ::
    namespace identifier { NamespaceMembers } ;
NamespaceMembers ::
    ExtendedAttributeList NamespaceMember NamespaceMembers
    ε
NamespaceMember ::
    RegularOperation
    readonly AttributeRest
    Const

The following IDL fragment defines a namespace.

namespace VectorUtils {
  readonly attribute Vector unit;
  double dotProduct(Vector x, Vector y);
  Vector crossProduct(Vector x, Vector y);
};

A JavaScript implementation would then expose a global VectorUtils data property which was a simple object (with prototype %Object.prototype%) with enumerable data properties for each declared operation, and enumerable get-only accessors for each declared attribute:

Object.getPrototypeOf(VectorUtils);                         // Evaluates to Object.prototype.
Object.keys(VectorUtils);                                   // Evaluates to ["dotProduct", "crossProduct"].
Object.getOwnPropertyDescriptor(VectorUtils, "dotProduct"); // Evaluates to { value: <a function>, enumerable: true, configurable: true, writable: true }.
Object.getOwnPropertyDescriptor(VectorUtils, "unit");       // Evaluates to { get: <a function>, enumerable: true, configurable: true }.

2.7. Dictionaries

A dictionary is a definition (matching Dictionary) used to define an ordered map data type with a fixed, ordered set of entries, termed dictionary members, where keys are strings and values are of a particular type specified in the definition.

dictionary identifier {
  /* dictionary_members... */
};

Dictionary instances do not retain a reference to their language-specific representations (e.g., the corresponding JavaScript object). So for example, returning a dictionary from an operation will result in a new JavaScript object being created from the current values of the dictionary. And, an operation that accepts a dictionary as an argument will perform a one-time conversion from the given JavaScript value into the dictionary, based on the current properties of the JavaScript object. Modifications to the dictionary will not be reflected in the corresponding JavaScript object, and vice-versa.

Dictionaries must not be used as the type of an attribute or constant.

A dictionary can be defined to inherit from another dictionary. If the identifier of the dictionary is followed by a colon and a identifier, then that identifier identifies the inherited dictionary. The identifier must identify a dictionary.

A dictionary must not be declared such that its inheritance hierarchy has a cycle. That is, a dictionary A cannot inherit from itself, nor can it inherit from another dictionary B that inherits from A, and so on.

dictionary Base {
  /* dictionary_members... */
};

dictionary Derived : Base {
  /* dictionary_members... */
};

The inherited dictionaries of a given dictionary D is the set of all dictionaries that D inherits from, directly or indirectly. If D does not inherit from another dictionary, then the set is empty. Otherwise, the set includes the dictionary E that D inherits from and all of E’s inherited dictionaries.

Dictionary members can be specified as required, meaning that converting a language-specific value to a dictionary requires providing a value for that member. Any dictionary member that is not required is optional.

Note that specifying dictionary members as required only has an observable effect when converting other representations of dictionaries (like a JavaScript value supplied as an argument to an operation) to an IDL dictionary. Specification authors should leave the members optional in all other cases, including when a dictionary type is used solely as the return type of operations.

A given dictionary value of type D can have entries for each of the dictionary members defined on D and on any of D’s inherited dictionaries. Dictionary members that are specified as required, or that are specified as having a default value, will always have such corresponding entries. Other members' entries might or might not exist in the dictionary value.

In the JavaScript binding, a value of undefined for the property corresponding to a dictionary member is treated the same as omitting that property. Thus, it will cause an error if the member is required, or will trigger the default value if one is present, or will result in no entry existing in the dictionary value otherwise.

As with operation argument default values, it is strongly encouraged not to use true as the default value for boolean-typed dictionary members, as this can be confusing for authors who might otherwise expect the default conversion of undefined to be used (i.e., false). [API-DESIGN-PRINCIPLES]

An ordered map with string keys can be implicitly treated as a dictionary value of a specific dictionary D if all of its entries correspond to dictionary members, as long as those entries have the correct types, and there are entries present for any required or defaulted dictionary members.

dictionary Descriptor {
  DOMString name;
  sequence<unsigned long> serviceIdentifiers;
};

A Descriptor dictionary could be created as in the following steps:

  1. Let identifiers be « 1, 3, 7 ».

  2. Return «[ "name" → "test", "serviceIdentifiers" → identifiers ]».

Each dictionary member (matching DictionaryMember) is specified as a type (matching Type) followed by an identifier (given by an identifier token following the type). The identifier is the key name of the key–value pair. If the Type is an identifier followed by ?, then the identifier must identify an interface, enumeration, callback function, callback interface or typedef. If the dictionary member type is an identifier not followed by ?, then the identifier must identify any one of those definitions or a dictionary.

If the type of the dictionary member, after resolving typedefs, is a nullable type, its inner type must not be a dictionary type.

dictionary identifier {
  type identifier;
};

If the identifier for an optional dictionary member is followed by a U+003D (=) and a value (matching DefaultValue), then that gives the dictionary member its default value, which is the value used by default when author code or specification text does not provide a value for that member.

dictionary identifier {
  type identifier = "value";
};

When a boolean literal token (true or false), the null token, an integer token, a decimal token, one of the three special floating point literal values (Infinity, -Infinity or NaN), a string token, the two token sequence [], or the two token sequence {} is used as the default value, it is interpreted in the same way as for an operation’s optional argument default value.

If the type of the dictionary member is an enumeration, then its default value if specified must be one of the enumeration’s values.

If the type of the dictionary member is preceded by the required keyword, the member is considered a required dictionary member.

dictionary identifier {
  required type identifier;
};

The type of a dictionary member must not include the dictionary it appears on. A type includes a dictionary D if at least one of the following is true:

As with interfaces, the IDL for dictionaries can be split into multiple parts by using partial dictionary definitions (matching partial Dictionary). The identifier of a partial dictionary definition must be the same as the identifier of a dictionary definition. All of the members that appear on each of the partial dictionary definitions are considered to be members of the dictionary itself.

dictionary SomeDictionary {
  /* dictionary_members... */
};

partial dictionary SomeDictionary {
  /* dictionary_members... */
};

Note: As with partial interface definitions, partial dictionary definitions are intended for use as a specification editorial aide, allowing the definition of an interface to be separated over more than one section of the document, and sometimes multiple documents.

The order of the dictionary members on a given dictionary is such that inherited dictionary members are ordered before non-inherited members, and the dictionary members on the one dictionary definition (including any partial dictionary definitions) are ordered lexicographically by the Unicode codepoints that comprise their identifiers.

For example, with the following definitions:

dictionary B : A {
  long b;
  long a;
};

dictionary A {
  long c;
  long g;
};

dictionary C : B {
  long e;
  long f;
};

partial dictionary A {
  long h;
  long d;
};

the order of the dictionary members of a dictionary value of type C is c, d, g, h, a, b, e, f.

Dictionaries need to have their members ordered because in some language bindings the behavior observed when passing a dictionary value to a platform object depends on the order the dictionary members are fetched. For example, consider the following additional interface:

[Exposed=Window]
interface Something {
  undefined f(A a);
};

and this JavaScript code:

var something = getSomething();  // Get an instance of Something.
var x = 0;

var dict = { };
Object.defineProperty(dict, "d", { get: function() { return ++x; } });
Object.defineProperty(dict, "c", { get: function() { return ++x; } });

something.f(dict);

The order that the dictionary members are fetched in determines what values they will be taken to have. Since the order for A is defined to be c then d, the value for c will be 1 and the value for d will be 2.

The identifier of a dictionary member must not be the same as that of another dictionary member defined on the dictionary or on that dictionary’s inherited dictionaries.

No extended attributes are applicable to dictionaries.

Partial ::
    partial PartialDefinition
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
Dictionary ::
    dictionary identifier Inheritance { DictionaryMembers } ;
DictionaryMembers ::
    DictionaryMember DictionaryMembers
    ε
DictionaryMember ::
    ExtendedAttributeList DictionaryMemberRest
DictionaryMemberRest ::
    required TypeWithExtendedAttributes identifier ;
    Type identifier Default ;
PartialDictionary ::
    dictionary identifier { DictionaryMembers } ;
Default ::
    = DefaultValue
    ε
DefaultValue ::
    ConstValue
    string
    [ ]
    { }
    null
    undefined
Inheritance ::
    : identifier
    ε

One use of dictionary types is to allow a number of optional arguments to an operation without being constrained as to the order they are specified at the call site. For example, consider the following IDL fragment:

[Exposed=Window]
interface Point {
  constructor();
  attribute double x;
  attribute double y;
};

dictionary PaintOptions {
  DOMString fillPattern = "black";
  DOMString strokePattern;
  Point position;
};

[Exposed=Window]
interface GraphicsContext {
  undefined drawRectangle(double width, double height, optional PaintOptions options);
};

In a JavaScript implementation of the IDL, an Object can be passed in for the optional PaintOptions dictionary:

// Get an instance of GraphicsContext.
var ctx = getGraphicsContext();

// Draw a rectangle.
ctx.drawRectangle(300, 200, { fillPattern: "red", position: new Point(10, 10) });

The members of PaintOptions are optional. If fillPattern is omitted, the definition of drawRectangle can assume that it has the given default values and not include explicit wording to handle its omission. drawRectangle needs to explicitly handle the case where strokePattern and position are omitted.

2.8. Exceptions

An exception is a type of object that represents an error and which can be thrown or treated as a first class value by implementations. Web IDL has a number of pre-defined exceptions that specifications can reference and throw in their definition of operations, attributes, and so on. Custom exception types can also be defined, as interfaces that inherit from DOMException.

A simple exception is identified by one of the following types:

These correspond to all of the JavaScript error objects (apart from SyntaxError and Error, which are deliberately omitted as they are reserved for use by the JavaScript parser and by authors, respectively). The meaning of each simple exception matches its corresponding error object in the JavaScript specification.

The second kind of exception is a DOMException, which provides further programmatically-introspectable detail on the error that occurred by giving a name. Such names are drawn from the DOMException names table below.

As DOMException is an interface type, it can be used as a type in IDL. This allows for example an operation to be declared to have a DOMException return type. This is generally a bad pattern, however, as exceptions are meant to be thrown and not returned.

The final kind of exception is a derived interface of DOMException. These are more complicated, and thus described in the dedicated section § 2.8.2 DOMException derived interfaces.

Simple exceptions can be created by providing their type name. A DOMException can be created by providing its name followed by DOMException. Exceptions can also be thrown, by providing the same details required to create one. In both cases, the caller may provide additional information about what the exception indicates, which is useful when constructing the exception’s message.

Here is are some examples of wording to use to create and throw exceptions. To throw a new simple exception whose type is TypeError:

Throw a TypeError.

To throw a new DOMException with name "NotAllowedError":

Throw a "NotAllowedError" DOMException.

To create a new DOMException with name "SyntaxError":

Let object be a newly created "SyntaxError" DOMException.

To reject a promise with a new DOMException with name "OperationError":

Reject p with an "OperationError" DOMException.

An example of including additional information used to construct the exception message would be:

Throw a "SyntaxError" DOMException indicating that the given value had disallowed trailing spaces.

Such additional context is most helpful to implementers when it is not immediately obvious why the exception is being thrown, e.g., because there are many different steps in the algorithm which throw a "SyntaxError" DOMException. In contrast, if your specification throws a "NotAllowedError" DOMException immediately after checking if the user has provided permission to use a given feature, it’s fairly obvious what sort of message the implementation ought to construct, and so specifying it is not necessary.

The resulting behavior from creating and throwing an exception is language binding specific.

See § 3.14.3 Creating and throwing exceptions for details on what creating and throwing an exception entails in the JavaScript language binding.

2.8.1. Base DOMException error names

The DOMException names table below lists all the allowed names for instances of the base DOMException interface, along with a description of what such names mean, and legacy numeric error code values.

Interfaces inheriting from