Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider syntactic changes to WebIDL to make it more "JavaScript-y" #485

Open
littledan opened this issue Dec 5, 2017 · 26 comments
Open
Labels

Comments

@littledan
Copy link
Collaborator

WebIDL's syntax derives from the history of OMG and CORBA, though it has been gradually deviating from that. There are still several superficial changes that could be made to try to make WebIDL more intuitive for JavaScript programmers, such as:

  • Write class instead of interface for exposed interfaces
  • Replace : with extends
  • Use getter/setter method syntax instead of attribute
  • Consider other syntax for optional, e.g., = undefined after a parameter
  • Consider value : Type instead of Type value, a la TypeScript/Flow (not actually JS but many developers are familiar)
  • Rename some types, e.g., DOMString => String
  • Provide some common aliases, e.g., unrestricted double => Number
  • Extended attributes in square brackets looks like computed property names, and similar syntax has been rejected for addition in JS due to ambiguity in an LR(1) grammar; consider some other syntax for extended attributes, such as @attribute(arg)
  • And probably more things

This is potentially a lot of changes, and I'm not sure if they would "pay for themselves" given the complexity of implementing them across tooling. However, they could make WebIDL more accessible for ordinary JavaScript developers and improve interaction between developers, spec authors and implementers.

I believe there are open bugs for some of these, but I haven't looked them up yet; please feel free to edit and add cross-references.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Dec 5, 2017

Some prior work at https://github.com/w3ctag/jsidl and I thought there were other similar proposals around but can't locate them right now.

Use getter/setter method syntax instead of attribute

There is no getter/setter method syntax that allows just declaring the method without specifying its body. Furthermore, the getter/setter method syntax obviously doesn't include the type annotations WebIDL has. So presumably this just means some syntax similar to the getter/setter syntax, but details TBD?

@littledan
Copy link
Collaborator Author

So presumably this just means some syntax similar to the getter/setter syntax, but details TBD?

Yes, to go crazy with this combined with the above suggestions, it could be something like

class X {
  get y() : Type;
  set y(arg : Type);
}

@bzbarsky
Copy link
Collaborator

bzbarsky commented Dec 5, 2017

So one problem with the get/set proposal is the number of random tokens in there that aren't actually needed to communicate information (e.g. the parens). ES has them to make getters/setters look like other functions (e.g. nothing keeps you from defining a setter that takes some number of arguments in ES).

On the bright side, this proposal would make it simple to create getters/setters where the type differs, which people have wanted a few times.

@kenchris
Copy link

kenchris commented Dec 6, 2017

What tools are we talking about? Blink and WebKit generates their interfaces from *.idl files, but those could be changed over time to match the newer syntax.

I guess respec and bikeshed would be the important tools to change, so let's see what @tabatkins and @marcoscaceres think

@littledan
Copy link
Collaborator Author

I think there are more tools than just that, e.g., @DanielRosenwasser mentioned to me that TypeScript has some sort of WebIDL importer. I imagine some IDEs may use WebIDL for code completion, but this is a guess and I don't really know that world. (But it's hard to imagine WebIDL tools being much more extensive and hard to update than JavaScript tools, and yet we change JS syntax...)

@tobie
Copy link
Collaborator

tobie commented Dec 7, 2017

For info, I file bugs with ReSpec, Bikeshed, WebIDL Parser, widlparser, and idlharness whenever there are grammar changes. If there are other tools that use GitHub issues for bug tracking and that want to be pinged whenever there's a grammar change, they should just let me know, I'll add them to the list.

@kenchris
Copy link

kenchris commented Dec 7, 2017

You should probably file at crbug.com/new the mozilla bugtracker etc as well

@tobie
Copy link
Collaborator

tobie commented Dec 7, 2017

We do. (Those seemed obvious, sorry for not mentioning them upfront.)

We track them too. Here for example: #472

@DanielRosenwasser
Copy link

@tobie if it's not trouble, https://github.com/Microsoft/TSJS-lib-generator/ might be a good place to ping us about grammar changes.

@tobie
Copy link
Collaborator

tobie commented Dec 19, 2017

@DanielRosenwasser done.

@littledan
Copy link
Collaborator Author

Another change for this bucket: rather than using _identifier as an escape, use "identifier".

@bzbarsky
Copy link
Collaborator

bzbarsky commented Dec 8, 2018

I think things like:

void foo(long "optional");

would look a little weird...

@littledan
Copy link
Collaborator Author

@bzbarsky Yeah, they would--is there any particular need to use these names as parameters? I'd imagine they are most useful as method names.

@bzbarsky
Copy link
Collaborator

bzbarsky commented Dec 8, 2018

is there any particular need to use these names as parameters

Where "these names" is "any keyword that is not in https://heycam.github.io/webidl/#prod-ArgumentNameKeyword", right?

Unfortunately, the list of keywords doesn't seem to be in any one place in the spec; it's sort of scattered as terminal symbols in the grammar. So I can't tell whether there are other keywords which are not in ArgumentNameKeyword and hence would need escaping in argument names. And I guess if there are we should add them to ArgumentNameKeyword.

OK, so maybe what's needed to decide anything here is a list of places in the spec which use identifiers without escape-hatches like ArgumentNameKeyword...

It doesn't help that "foo" is an existing production (named string) in the grammar, so presumably all places that use identifier where we want to allow this sort of escape would need to change to use identifier | string, with rules for how to convert the string to an identifier.

@littledan
Copy link
Collaborator Author

OK, sounds like I misunderstood. I thought the _ feature was for operation/method names, but sounds like it's for argument names (is it really needed at all in this case?). Thanks for explaining.

@tabatkins
Copy link
Contributor

It's for all of those, and other places that accept naming-keywords that might be confused for syntax-keywords. Interface names, attributes, methods, arguments, types, etc. all use the _ marker when they need to use a name already claimed by syntax.

@yuki3
Copy link

yuki3 commented Dec 19, 2018

Can I add another but pretty similar/related idea about "constructor" here?

The idea is to declare IDL interface's constructors without using extended attributes.

current syntax:

[Constructor(),
 Constructor(Arg arg)]
interface X {}

proposed syntax (details TBD):

interface X {
  [ExtAttr1] constructor();
  [ExtAttr2] constructor(Arg arg);
}

The key point here is that, with the proposed way above, we can annotate constructors with extended attributes respectively (like [ExtAttr1] and [ExtAttr2] above). For example, we can make one of constructors [SecureContext]. (By the way, Chromium team has actual demands to specify Chromium/Blink-specific extended attributes.)

In the above example, I used constructor as a keyword, but I'm fine with any syntax as long as we can specify extended attributes.

@littledan
Copy link
Collaborator Author

I like this idea in #485 (comment). Do you have a reference for details of this requirement in Blink?

@yuki3
Copy link

yuki3 commented Dec 19, 2018

I'm sorry that I don't have a handy public reference. But I remember that some people wanted to make some constructors [RuntimeEnabled=FEATURE_NAME], which is a Blink-specific extended attribute. With this extended attribute, we can enable a certain experimental constructor only for those who explicitly opt-in the experiment. We somehow managed it with a hack instead of the extended attribute in past, that was painful and unfortunate.

@bzbarsky
Copy link
Collaborator

For example, we can make one of constructors [SecureContext].

I don't see how. [SecureContext] controls exposure. You can't have different [SecureContext] settings on different overloads of the same function, because there is only one thing being exposed in JS. This is explicitly specified at https://heycam.github.io/webidl/#SecureContext for that exact reason.

You can, of course, add secure context checks in the actual implementation steps...

Does Chrome's RuntimeEnabled thing work on a per-overload basis? What happens if you set it on only some overloads of a single method?

Past that, I think the proposal is not unreasonable; I've wanted something similar in Gecko once or twice, precisely so I could add extended attributes. I just want us to be clear about expectations about what extended attributes will or will not work, is all.

@littledan
Copy link
Collaborator Author

@bzbarsky I'm curious, do you remember which extended attributes you were trying to add in that case?

@bzbarsky
Copy link
Collaborator

I suspect [Throws] (which we use in Gecko to annotate methods whose actual algorithm steps can throw, so bindings have complete visibility into whether a method can throw or not in various circumstances). Right now Gecko assumes any constructor might throw...

@yuki3
Copy link

yuki3 commented Dec 20, 2018

I don't see how. [SecureContext] controls exposure.

Oops, [SecureContext] was a bad example. Never mind.

Does Chrome's RuntimeEnabled thing work on a per-overload basis? What happens if you set it on only some overloads of a single method?

Yes, it works on a per-overload basis. [RuntimeEnabled] changes an effective overload set. Depending on whether the flag is enabled or not, an invocation might cause a TypeError or extra type conversion.

For example,

interface X {
  [RuntimeEnabled=F] void foo(long);
  void foo(DOMString);
}

foo(42) will be treated as an invocation of foo(long) if F is enabled, otherwise as foo(DOMString) with a conversion from 42 to "42".

IIRC, [OriginTrial] is another example we wanted to apply to constructor. [OriginTrial] also affects an effective overload set.

@tabatkins
Copy link
Contributor

Yeah, I'd love to have the constructor just be a method, either named after the class or named "constructor" a la js.

interface Foo {
  Foo Foo(...);
  Foo constructor(...);
};

Maybe not with the return type, as that's both obvious and shouldn't be changed.

@tabatkins
Copy link
Contributor

(We could probably leave named constructors as an interface extended attribute, since they're legacy anyway. Or additionally add some way to indicate that a method is a constructor, and then just define named constructors as methods on Window or whatever.)

@ExE-Boss
Copy link
Contributor

ExE-Boss commented May 5, 2019

I think we could keep interface since it’s a reserved keyword in JavaScript and is used in TypeScript to denote class shapes:

// X.ts
export default interface X {
	y: Type;
}

// XImpl.ts
import type X from './X.js';
class XImpl implements X {
	private #y: Type;

	get y(): Type {
		return this.#y;
	}

	set y(arg: Type) {
		this.#y = arg;
	}
}

export {
	XImpl as implementation,
};

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

No branches or pull requests

9 participants