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

Should JSON modules be frozen? #3

Closed
littledan opened this issue May 8, 2020 · 22 comments · Fixed by tc39/proposal-import-attributes#74
Closed

Should JSON modules be frozen? #3

littledan opened this issue May 8, 2020 · 22 comments · Fixed by tc39/proposal-import-attributes#74

Comments

@littledan
Copy link
Member

@Jack-Works recently and @robpalme previously suggested that JSON modules be frozen. We previously concluded that they would not be frozen.

However, in the context of JSON modules potentially standardized by TC39, maybe we could reconsider, and freeze JSON modules this time. I would be OK either way, personally.

The PR for JSON modules includes them as un-frozen. This wouldn't necessary prohibit a host/implementation from going around and freezing it (depending on the metaphysics of spec reading), but it'd be nice to really have a solid, cross-environment decision one way or another.

I want to argue that this is something that we can iterate on during Stage 2 and need to decide on before Stage 3.

@littledan
Copy link
Member Author

I see some emoji-reacts but what I really want is comments describing your opinions and rationale!

@michaelficarra
Copy link
Member

I want to argue that this is something that we can iterate on during Stage 2 and need to decide on before Stage 3.

Ageed.

What are use-cases that are benefitted by having JSON modules not frozen?

@ljharb
Copy link
Member

ljharb commented May 8, 2020

The same use cases as currently requiring mutable json in node - using it as a shared bit of mockable data.

@michaelficarra
Copy link
Member

@ljharb You can mock with import maps.

@littledan
Copy link
Member Author

@ljharb Do you have any references for practical cases where this comes up in Node.js? It'd be helpful to understand concrete instances, if possible.

@jridgewell
Copy link
Member

I think it'd be pretty natural to want to mutate the returned data in some way, but whatwg/html#4315 (comment) makes me cautious. Maybe if we do deep-freeze, we provide a named export to get a fresh, mutable clone of the data?

import data, { makeMutable } from "./foo.json";

assert(Object.isFrozen(data));

assert(typeof makeMutable === 'function');
assert(typeof makeMutable() === 'object');
assert(!Object.isFrozen(makeMutable());
assert(makeMutable() !== makeMutable());

@ljharb
Copy link
Member

ljharb commented May 8, 2020

@michaelficarra import maps aren't in the language, so they aren't a viable solution.

@littledan nothing concrete; there's tons of code that requires JSON files though, and it shouldn't be too hard to find something that mutates it.

Either way, I'd be more in favor of every import of JSON providing a fresh but mutable object, rather than providing a deeply frozen one.

@caridy
Copy link

caridy commented May 8, 2020

Either way, I'd be more in favor of every import of JSON providing a fresh but mutable object, rather than providing a deeply frozen one.

I feel the same. Producing a deeply frozen has 3 major issues IMO:

  • users already have some expectation about objects
  • majority of the imported values today are mutable, this is related to the previous point on users expectations.
  • it makes it very hard for consumers of the json obj to manipulate them, e.g.: making a mutable copy of the json object from a deeply frozen one (a lot of JSON.parse(JSON.stringify(value)) go begin with.

@devsnek
Copy link
Member

devsnek commented May 8, 2020

If it is mutable we cannot produce a new object at each import location. Mutability aside, you really don't want more than one copy of a json module, since modules can't be easily gc'd.

@tilgovi
Copy link

tilgovi commented May 8, 2020

I'm drawn towards mutability because it seems most consist with what you would get if the default export of a module were an object. Even if you cannot modify the exports of a module namespace, you can modify the exported objects themselves. I don't see why it should be any different here just because the default export was synthetically generated by parsing JSON.

@Jack-Works
Copy link
Member

It seems like the imported JSON is per-Realm. If I change it in this Realm, that Realm will get the original version of it.

I think a JSON module return object with utils (makeMutable) in the above comment is a bit strange to me.

@littledan
Copy link
Member Author

@devsnek Why would we produce a new object at each import location? I guess that's technically permitted by the spec (from each different referrer), but HTML would not do this, as it just uses the referrer to produce an absolute URL, which is the key in the module map. I think we should permit HTML to process JSON modules in a similar way.

@jridgewell Remember to use with type: "json" in the examples! I share @Jack-Works 's intuition that this feature is a bit overkill. I'd like to keep this proposal minimal and focus on the common case; you can always do JSON.parse on whatever you want if you need flexibility.

@Jack-Works The whole module map would be per-Realm in HTML and environments similar to it, as formalized in the Realm/HTML integration proposal. However, we don't have anything in these specs that requires separate Realms to have separate module maps. I'm not sure whether we should change that. But I think formalizing/requiring invariants that are already true in several JS environments is a bit of an orthogonal project to this proposal.

@devsnek
Copy link
Member

devsnek commented May 11, 2020

@littledan I don't want a new object at each location, I want the same mutable object everywhere (per realm)

@littledan
Copy link
Member Author

@devsnek Good, that's what the current proposal is. Can you say why you want this?

@hax
Copy link
Member

hax commented May 11, 2020

Maybe import data from "./foo.json" with type: "json", mutable: true ? 😆

(If I already need to write with type: "json" everytime, it's nothing big to write a more attribute...)

@ljharb
Copy link
Member

ljharb commented May 11, 2020

Mutability is the default in JS, you have to ask to Object.freeze something. Also, I'd expect most people to not write type json, but to let their transpiler/bundler add it in, since deno or the browser are the only places you can't know "it's json" from the filesystem.

@devsnek
Copy link
Member

devsnek commented May 11, 2020

I don't directly care whether it is mutable or not, but I do care that it is the same object everywhere, and I care about memory usage. It is already not ideal to import json, as I said above, and I don't want to compound that with having to copy the structure to modify it.

@littledan
Copy link
Member Author

@devsnek Good thing no one in this thread has proposed that it'd be a separate object on each import by default. I agree that that would be very weird.

@ljharb
Copy link
Member

ljharb commented May 12, 2020

@littledan i suggested that in https://github.com/tc39/proposal-module-attributes/issues/54#issuecomment-625946943 - and I’d find it less weird than making it frozen.

@littledan
Copy link
Member Author

littledan commented May 13, 2020

@ljharb Oops, I missed that comment. Would you be OK with not doing that, for the reasons @devsnek articulated, and to be consistent with how many environments do caching (based on normalizing the path and then using that as the cache key)?

@ljharb
Copy link
Member

ljharb commented May 13, 2020

Of course; I’m saying that I’d prefer the bad outcome of “always fresh” over the worse outcome of “frozen”. I think it should just be a realm-wide mutable object.

@littledan
Copy link
Member Author

OK, given this discussion, I'm going to leave the proposal as a Realm-wide mutable object for now. Let's keep this open to discuss alternatives; we can also talk about it at the next TC39 meeting where module attributes are discussed.

I'd like to consider the frozen vs not-frozen question to be something that's an important detail to figure out before Stage 3, but that we can go to Stage 2 just based on the "core" decisions (namely, that JSON modules can be imported by with type: "json" in all environments, and that they consist of a single default export). If you disagree with this categorization, I'd like to hear from you!

xtuc referenced this issue in tc39/proposal-import-attributes Jun 23, 2020
xtuc referenced this issue in tc39/proposal-import-attributes Jun 23, 2020
xtuc referenced this issue in tc39/proposal-import-attributes Jul 8, 2020
@dandclark dandclark transferred this issue from tc39/proposal-import-attributes Aug 27, 2020
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

Successfully merging a pull request may close this issue.

9 participants