tc39 / proposal-built-in-modules

BSD 2-Clause "Simplified" License
892 stars 25 forks source link

JavaScript standard library contents #16

Open littledan opened 5 years ago

littledan commented 5 years ago

The JavaScript standard library is very minimal. Is this how it should be? What should we add?

Note, the purpose of this repository is to develop the infrastructure for built-in modules, not the contents. However, I know many of you have ideas for the contents as well, so let's brainstorm those in this issue exclusively.

Mouvedia commented 5 years ago

enhanced promises

@littledan is this issue a dump for proposals? If that's the case I don't think we will ever be able to close it.

ljharb commented 5 years ago

Changing something that’s already in the language would need its own proposal; i think the standard library would be for adding new things.

Mouvedia commented 5 years ago

Changing something that’s already in the language would need its own proposal

@ljharb If the change is too radical or breaking, it has to be externalized: an alternative with another name to avoid confusion; future comes to mind in my case.

littledan commented 5 years ago

I meant this as a brainstorming thread. What we talk about here might graduate into proposals. As @ljharb says, let's try to focus on additions of new features, rather than changes to existing things (it's not clear how to expose what you're talking about as a built-in module). If this thread gets too unwieldy, we can close it.

Mouvedia commented 5 years ago

Composable?

jasnell commented 5 years ago

WHATWG URL should be normative. await JSON.parse() and await JSON.stringify() or similar

NarHakobyan commented 5 years ago

Would be nice to have promise cancelation

Mouvedia commented 5 years ago

uuid?

Mouvedia commented 5 years ago

Anything that validates ECMAScript internal stuff. e.g. https://mothereff.in/js-variables

littledan commented 5 years ago

@Mouvedia Would uuid make sense as part of WebCrypto? https://github.com/w3c/webcrypto/issues/215

littledan commented 5 years ago

@mathiasbynens 's Unicode RegExp properties should help with making that checker more efficient!

Mouvedia commented 5 years ago

That validator is just an example. My point is that the language should expose its own validators/assertors.

That would permit to have a basis for other interfaces (like the DOM). e.g. I had to make my own class/id assertors (html/css)

Mouvedia commented 5 years ago

@Mouvedia Would uuid make sense as part of WebCrypto? w3c/webcrypto#215

I don't know. Last time I checked the polyfill was enormous—it was almost impractical.

littledan commented 5 years ago

@Mouvedia Well, the idea would be that you just use uuid if you don't have the built-in one. (uuid actually uses WebCrypto in browsers today.)

Mouvedia commented 5 years ago

The idea of futures is something that should be pursued; in the same way that XMLHttpRequest was retroactively redefined in terms of fetch, we could have Promise be redefined in terms of Future where futures are more granular and hence give more control to the user.

@NarHakobyan https://github.com/tc39/proposal-javascript-standard-library/issues/16#issuecomment-447916074

JonForest commented 5 years ago

It would be great to be able to access object properties without having to do something along the lines of

const prop2 = obj && obj.prop1 && obj.prop1.prop2

Something like the lodash _.get function, or Angular's elvis operator in the templates (obj?.prop1?.prop2?) I'm not super-keen on _.get because it's turning the property path into a string, which is not great from a typing and build checking point of view, but I use it as an example of desired functionality.

decadecity commented 5 years ago

My two longstanding bugbears with the JS standard library (going back to my pre-jQuery days) are:

  1. A better interface for dealing with cookies (i.e. doesn't involve directly manipulating a string - something like Web Storage).
  2. A parser/constructor for URLs like Python's urllib.parse (other languages' standard library methods for dealing with URLs are also available).

For a language that spends a lot of its time running in a browser these seem like obvious candidates for a standard library.

littledan commented 5 years ago

@decadecity I'm wondering if the solutions at the web level, currently shipping in browsers, are enough for your use case.

  1. Does Web Storage solve the issue for you, or are there remaining problems?
  2. Does the WHATWG URL API solve this issue for you?
littledan commented 5 years ago

@JonForest Have you see the optional chaining proposal? It's attempting to add that operator.

decadecity commented 5 years ago

@littledan

  1. Web Storage is fine for client side storage but doesn't do cookies :stuck_out_tongue: Directly manipulating the document.cookies string is a terrible API, I'd like to see something like the extension cookies API.
  2. The URL API looks like it's about right, thanks :+1:
littledan commented 5 years ago

@decadecity Work is ongoing to evolve the cookie API itself at https://github.com/WICG/cookie-store . TC39 is probably the wrong place to advance work in this area, as we focus on things that don't involve I/O. Cookies don't mean much outside of the Web.

anotheredward commented 5 years ago

In terms of what we can see people using, lodash is the most depended upon library that would be potentially appropriate to exist in core: https://www.npmjs.com/browse/depended

It's a bit harder to break down which functions are used the most, but you can get an idea here: https://www.npmjs.com/search?q=lodash&ranking=popularity

There is also a minimal version of the library: https://github.com/lodash/lodash/wiki/Build-Differences

StoneCypher commented 5 years ago

No, the JS standard library should not be minimal. Part of the reason there's so many variations on the underscore theme is that there's a lot of really basic stuff missing from the language (like deep copy.)

Unfortunately it's not clear where feature requests belong. While I was writing out a flood, I was told "not here. Maybe on issue 16."

There's dozens of easy one-liners that would massively improve the language if gatekeepers would permit them

StoneCypher commented 5 years ago

I'll copy pasta a bunch right now if someone tells me where to put them

littledan commented 5 years ago

@StoneCypher I'm glad you came here to do additional brainstorming for contents. For JavaScript one-liners, maybe could you make your own repository or gist for development and link to it from here?

martinheidegger commented 5 years ago

Somehow I feel like the input from @kgryte could be useful to this discussion ;)

StoneCypher commented 5 years ago

Would be really nice if there was an official place to give people recommendations for a more complete standard libary

StoneCypher commented 5 years ago

There's a whole lot of donation languishing in repos that gatekeepers don't look for

JS could be an amazingly easier language with very little work on anyone's part if the gatekeepers would facilitate donation

StoneCypher commented 5 years ago

In erlang, for example, there is a bug tracker where I can go, add a ticket with some code and some appropriate tags, and if my code isn't garbage and makes sense, there's a good chance it'll show up in the next standard library under some very different name

Recommendations I gave to Ian Hicks almost 20 years ago and gave code for are being invented this year and treated as important and ground breaking ☹️

Javascript should have a process for letting people who aren't friends with standards maintainers be helpful too

StoneCypher commented 5 years ago

I'm just going to go ahead and put what I wrote yesterday into a ticket

If I put it in my own repo nobody will ever look at it and it will die on-site

jhpratt commented 5 years ago

I'm surprised no one has brought this up yet — the much-proposed range generator function would be a great addition, and presumably without much opposition. Following Python's semantics would make sense.

ljharb commented 5 years ago

@jhpratt Array.build was proposed long ago, and might be a candidate for picking up again.

jhpratt commented 5 years ago

@ljharb I think it would be better to have it as a generator to avoid memory constraints, no? Though having a map function would be useful in certain cases, I imagine.

lachlanhunt commented 5 years ago

More useful functions for working with generators and iterables should be included.

Standard sequence generators:

Generator modifiers:

Some of these are based on existing Array or lodash/underscore methods for Arrays, which are also useful for generators so that they can be run lazily as items are pulled from the generator, rather than first converting to an array.

I've implemented these, and more, in my own library. I've listed just some of the most useful for inclusion in a standard library.

https://github.com/lachlanhunt/generator-utilities/ (Not everything in there would be appropriate for inclusion, though)

Edit: Fixed syntax error in code sample.

viktor-ku commented 5 years ago

If you have general range it isn't clear what type it's gonna produce: array, maybe set, maybe weak set or any other current or future iterable? Why is it worse in your opinion than Array.range() or Set.range() hence adding methods to Array or Set directly without having to do this in standard lib? The same goes with len or take or map.

Question then arrives isn't it better to rename this proposal to enhance js builtin-ins?

StoneCypher commented 5 years ago

It's really unfortunate that Dan keeps closing my tickets without taking the time to understand them first, even though the ones that got talked over had community support :(

I am not alone in feeling that gatekeeping in JS is out of control

ProdigySim commented 5 years ago
  1. Get data from NPM and github looking at package.json dependencies and subdependencies
  2. Find the most depended-on libraries
  3. Filter by human to determine which ones would fit in a standard library

I think a Standard library for JS should seek to alleviate npm dependency issues.

Having a standard implementation for basic functionality that works in both Node and Browser environments would remove much of the need for simple NPM packages that increase the number of potential security events just by nature of distributed ownership.

lazarljubenovic commented 5 years ago

A bunch of things missing from Array's prototype:

Set operations are missing too (edit: been notified of an existing proposal). Since these are n-ary (n > 1), instead of methods like a.op(x).op(y) or a.op(...xs), static functions might make more sense:

Not sure if Array deserves these too.


Sorting with the default coercion to string is ridiculous; [111, 22, 3] is already sorted by default because strings are lexicographically ascending. Maybe some global common comparison functions? Eg. for numbers, [111, 22, 3].sort(Compare.number) where Compare.number is (a, b) => a > b ? -1 : 1).

Probably a sortBy would also come in handy so we don't have to arr.sort((a, b) => a.x.y.z > b.x.y.z ? -1 : 1) and instead do arr.sortBy(a => a.x.y.z).


Add more data structures: Queue, Stack would be a good starting point, where implementations could choose more efficient storage strategies (eg. linked lists) instead of working with arrays and push/pop/unshift/shift.

Of course, LinkedList, Tree and Graph would be great addition as well.

The constructor of linked lists could tweak the exact type, with switches like circular and/or doubly-linked (or just introduce more constructors). Then we get things like get head, get tail, add to head, add to tail, remove from head, remove from tail, add after, add before.

Trees are interesting because the traversal of the DOM has improved a lot and it's quite pleasant to work with with all the things you can do to nodes. A lot of these operations have little to do with DOM-specific API and a lot to do with trees in general (parent, children, insertBefore, insertAfter, remove, contains, etc). They would be a starting point for more things to add to standard library such as BinarySearchTree, BTree, BPlusTree, etc, which would have all the operations you expect them to have.

Similar with graphs, lots of common operations to add, including things like loading and serializing to a matrix, etc.


By the way, I think we shouldn't talk about a single "standard library", but instead several of those. I mean, aren't Map, Set, Math, URL, etc. already "standard libraries"? They provide utilities for common tasks. Even Array, if it wasn't so tied to the low-level working of [] would be just a utility for working with arrays -- you could still write a for loop to Array#reverse.

ljharb commented 5 years ago

For set operations, see https://github.com/tc39/proposal-set-methods

joelgallant commented 5 years ago

Is the intention to bring any existing standard library into this import style?

I like this idea, but it would feel inconsistent if a subset of lodash, say, were to be added to the language in a different (import reserved path) way than others, like Math.

lazarljubenovic commented 5 years ago

I like this idea, but it would feel inconsistent if a subset of lodash, say, were to be added to the language in a different (import reserved path) way than others, like Math.

We could add the import style for Math as well and alias it back to global's Math?

emilianobovetti commented 5 years ago

There are so many implementations of Maybe/Option and Either/Result monads that I feel a standard library could be perfect fit for those.

renatoagds commented 5 years ago

@littledan Immutable API? I think we could take a look in Immutable.js and bring some ideas from there. We'll have a crash between Map and Set that's already implemented in JS, but could be a good point of start.

jbreckmckye commented 5 years ago

Like @emilianobovetti, I'd like better ways to handle non-existent values, perhaps using a Maybe monad.

Consider an optional object with recursively optional fields:

// Could be one of three things:
// 1. undefined
// 2. {name: 'Joanna', age: undefined}
// 3. {name: 'Joanna', age: {years: undefined}}
const user = await getUser();

const yearsOld = user.age.years; // will break 

If user was wrapped in a Maybe, we could query and manipulate its fields with no fear of typeErrors:

const maybeUser = await getUser();
const yearsOld = maybeUser
    .map(_ => _.age)
    .map(_ => _.years)
    .getOrElse('Not known');

This may become less compelling if tc39/proposal-optional-chaining advances from Stage 1.

bmarkovic commented 5 years ago

@jbreckmckye I don't see why optional chaining syntax couldn't be employed on "whatever-optional-type-is-chosen" to behave like similar operator does in Rust, and to behave as proposed on non-monadic objects (ie. return undefined). It would be semantically consistent, even if perhaps not fully transparent to new users at first, but then, it can't be less transparent to new users than optional types and Promises.

Speaking of Promises I personally also liked the idea of the ? operator returning undefined and discarding rejection when applied to awaited Promises i.e.

// if Promise is rejected result = undefined, move along
let result = await someFnThatReturnsPromise()? 
tristan-shelton commented 5 years ago

I would love to see deep get/set/copy as part of the standard library.

lazarljubenovic commented 5 years ago

The problem with deep copy is that it's difficult to determine how deep and what exactly you want to do. How do you "deep copy" a function? Do you carry the prototype into the copy? What about cloning things like DOM nodes? Not to mention circular structures -- graphs? trees? doubly linked lists? The only "proper" way to deep copy is having something along the lines of a copy constructor for everything (including authored classes).

maple3142 commented 5 years ago

How about having a function like assignDeep? (It will work like Object.assign, but deeper one.)

ljharb commented 5 years ago

I think a “structured clone” protocol might pave the way for “deep copy” operations without having to bake in answers for those questions.

tristan-shelton commented 5 years ago

@lazarljubenovic While I do agree those issues should be thought through I think that any model you pick would be less confusing for most developers than the shallow copy that we get as part of the standard library today.

There are also many reference implementations of deep copy/clone out there in the wild being used by legions of developers so those would probably be a good place to look for answers to some of those questions.