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

Use general key-value syntax, or a single string? #12

Closed
littledan opened this issue Nov 7, 2019 · 28 comments
Closed

Use general key-value syntax, or a single string? #12

littledan opened this issue Nov 7, 2019 · 28 comments
Milestone

Comments

@littledan
Copy link
Member

In the original thread at WICG/webcomponents#839, there are several suggestions of syntax which includes a single string, rather than key-value syntax. Let's discuss the advantages and disadvantages of this option in this thread.

For example, the syntax for an import statement could be:

import json from "./foo.json" as "json";

Advantages of a single string

Advantages of key-value syntax

  • Generalizes to other use cases (c.f., Use cases for module attributes besides module type #8). Additional module parameters was an idea tossed around from even before this issue, so even if we don't find one of those use cases persuading now, we have some circumstantial evidence that it may come up in the future.
  • If we don't provide a general k/v syntax, there's a chance that people will see the need to do so inside the string (as was already proposed for the module specifier, see Should a syntax within module specifiers be used for this data instead? #11)
  • The as keyword is likely to be pretty confusing, as it's also a keyword with completely different meaning in other parts of an import statement

My opinion is that the advantages of a general key-value syntax outweigh the advantages for a single string. It's circumstantial evidence (since this proposal doesn't suggest acting on any of them yet), but the relatively high number of other possible use cases points to a k/v syntax to me. This would be analogous to the decision to make import.meta an object, rather than just adding a syntax for import.meta.url.

@chicoxyzzy
Copy link
Member

Key-value syntax is definitely look like a more future proof solution to me. Also this will make static imports and dynamic imports look more consistent, or are there any other suggestions than import('module', { type: 'json' }) which look more like a single string solution for static imports?

@bahrus
Copy link

bahrus commented Nov 7, 2019

Could the type be treated as the default, but if more parameters need to be defined, switch to k/v syntax? I.e a hybrid approach? The analogy of the default export, which doesn't use braces when importing comes to mind.

@Janpot
Copy link

Janpot commented Nov 8, 2019

Can't there still be key/value syntax with a single string, if encoded as a querystring?

import json from "./foo.json" as "type=json&anotherOption=42";

// and default behavior
import json from "./foo.json" as "json";
// would be equivalent to
import json from "./foo.json" as "type=json";

@littledan
Copy link
Member Author

littledan commented Nov 8, 2019

@Janpot We could do that. My feeling is that more sub-syntaxes will lead to more problems, from a developer experience perspective, from possible diversity/bugs in parsers, etc.

@Janpot
Copy link

Janpot commented Nov 8, 2019

My feeling is that it would leave more freedom to hosts/compilers on how to parse that string. My understanding is that the spec doesn't dictate how the module identifier is interpreted, I feel like in the same way it could leave freedom on how the module attributes are interpreted.

@littledan
Copy link
Member Author

Well, this comes a bit in contrast with the goals articulated in #10

@Janpot
Copy link

Janpot commented Nov 8, 2019

I see. fwiw, I didn't necessarily mean "freedom" as in "no consensus". I meant it more like "allow enough escape hatch for people to come up with ideas that we didn't think of today"

@bmeck
Copy link
Member

bmeck commented Nov 8, 2019

I'd like to call out editor UX here. Key-Value will lead to better completions if we ever have multiple attributes (which I would consider a mandate for this feature personally). Even today I am given sub-par UX with import statements due to their design and would not like to have another UX pitfall here for import.

@Janpot
Copy link

Janpot commented Nov 8, 2019

@bmeck Are you talking about it being hard to autocomplete the import since you type the module specifier last? As in, it would be more ergonomic to do:

from 'lodash' import { groupBy };

@bmeck
Copy link
Member

bmeck commented Nov 8, 2019

@Janpot that syntax allows tooling to better complete the code as you type, which is my concern yes.

@littledan
Copy link
Member Author

@bmeck I am with you on completions. I think you should usually not have to type the type at all if using editor completions.

@thw0rted
Copy link

thw0rted commented Nov 14, 2019

Has anybody made a strong argument against supporting both?

import j1 from "./foo.json" as "json";
import j2 from "./foo.json" as {type: "json", bar: "baz"};
const j3 = import("./foo.json", "json");
const j4 = import("./foo.json", {type: "json", bar: "baz"});

The thing I keep coming back to is that nobody can give me a concrete example of what the bar attribute should be. Of course it makes sense to save those 6 characters if the proposal never grows beyond type:, but if another attribute comes along and is not only useful but more commonly specified, having a "shorthand version" that's always interpreted as being the type will seem short-sighted in retrospect. At this point, to me, the opposite seems more likely: that we're currently over-engineering a solution for the general case (bag of key-value attributes) when the immediate need is for a simple case (exactly one attribute).

@littledan
Copy link
Member Author

Well, the basic concern would be that this goes in contrast with goals of minimalism. In the OP, I had some concerns with using as as a keyword here as well.

@xtuc
Copy link
Member

xtuc commented Nov 14, 2019

@thw0rted I think there are many use case for more than one argument: #22 or #16 (comment) are one of them in this repo.

@bmeck
Copy link
Member

bmeck commented Nov 14, 2019

I'd like to second the contrast of minimalism.

If you look at things like how default exports work in JS, they actually add quite a bit of complexity for a programmer to learn even if they are a common usage when importing modules. I find the usefulness of having 2 forms of imports to be plausible, but do not see such currently with module attributes as not all environments are even seeking to use the same attributes for the same purposes/reasoning currently.

@ljharb
Copy link
Member

ljharb commented Nov 14, 2019

I also would prefer minimalism (to me, default as a name is the confusion, not the existence of defaults, but my conclusion here is the same)

@littledan
Copy link
Member Author

After thinking about this a bit more, and chatting with @xtuc @dandclark and @MylesBorins offline, I'm thinking that it might make sense to start with the simple as "string" form, with a potential follow-on proposal to permit more complex attributes, like as {type: "json", key2: "value2}.

Advantages:

  • It feels more ergonomic to have the shorter form of just as rather than the longer with type:
  • This combines the simplicity of as with the flexibility and forward-looking aspects of the key-value syntax, that scales to multiple keys and values
  • There's less risk of cross-environment divergence if we initially restrict to a single string for module type.

Disadvantages:

  • It could be controversial to nail down exactly what is "constant enough" for an object literal, or be surprising to have object literals that are required to be "constant". (I can think of a "constant enough" definition that I like, but I'm not sure if everyone else likes it.)
  • as looks a bit funny before a complex literal; we may be better off with some other word, if we want to reuse it.

@xtuc and @dandclark suggested that for might be an alternative for as which makes sense with complex things on either side, but @MylesBorins pointed out that, even reusing as, the syntax is far from ambiguous: It switches based on whether as comes before or after the module specifier.

Thoughts?

@jridgewell
Copy link
Member

I thought the committee specifically didn't want to tie this to import types, and wanted to explore generic metadata attached to imports? https://github.com/tc39/notes/blob/master/meetings/2019-12/december-5.md#conclusions

I'm kinda disappointed to see us taking this route, since metadata on types would have been useful. Eg, TypeScript and Flow marked type-only imports, Babel could mark lazy imports, etc.

@littledan
Copy link
Member Author

@jridgewell The proposal leaves non-string metadata open for expansion into objects. In my mind, this is a key requirement, that we're not locking ourselves into just a string. But the idea is to start with a string, and make this further expansion when we are very solid on the use cases for other things (even though we have plenty of ideas).

@bmeck
Copy link
Member

bmeck commented Jan 24, 2020

I've stated in other issues that only tailoring to the web specific type attribute is not appealing. If the intent is not to include the ability to have multiple attributes in this proposal but instead in a follow on proposal I would not be comfortable moving forward.

@littledan
Copy link
Member Author

OK, given the aim of avoiding making the import types special, I'd like to conclude on the general key/value syntax, as is currently in master in this repository. I see this as one of the core questions that we'd be affirming consensus on for Stage 2.

@littledan littledan added this to the stage 2 milestone May 20, 2020
@xtuc
Copy link
Member

xtuc commented Jun 13, 2020

We decided to go with the key-value syntax and reached consensus for stage 2.

@jerrygreen
Copy link

jerrygreen commented Sep 29, 2020

Weird it reached consensus.

You have this in readme:

We propose to omit this generalization in the initial proposal, as a key/value list of strings already affords significant flexibility to start, but we're open to a follow-on proposal providing this kind of generalization

So why complicating the syntax, if you're already committed to "omit generalization"? What if it will come out that the type is sufficient, and there wouldn't be follow-on proposal? We will simply end up with weird syntax, having some object-like literal with one usable key: type.

Imo this code is enough for this particular proposal:

import json from "./foo" as "json";

And if another proposal will come, with support of some useful keys, they will have to bring some "assertions 2.0" with this object-like notation along with it, making key-value notation also available.

I personally think that there's too small chance for more keys to be real useful for assertions, too small to bringing this generalization straight away.

Sorry for notifying a closed thread but I had to say it.

@Jack-Works
Copy link
Member

If the JSON module proposal is requiring the host must interpret "type: json" as JSON, it means "type" is special. Maybe we can make as "string literal" as a shorthand of "type: 'string literal'"

@ljharb
Copy link
Member

ljharb commented Nov 21, 2020

That specialness is a quality of the specification though, not necessarily the runtime - a host might have many assertions available that operate the same way as “type”, and to a user on that host, “type” wouldn’t be special at all.

@kwebble
Copy link

kwebble commented Jul 23, 2022

As a developer, not someone who creates a language, When I see a literal string value I expect it can to be using an expression, is dynamic at runtime or can be taken from a variable. Please do not mix user code with language definition.

@ljharb
Copy link
Member

ljharb commented Jul 23, 2022

That expectation already doesn’t apply to the specifier (the part after the “from”).

@kwebble
Copy link

kwebble commented Jul 24, 2022

True, and I have the same objections about that. Whitespace as separator seems good enough for me.

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

No branches or pull requests