const at = (arr, i) => i >= 0 ? arr[i] : arr[arr.length + i];
Why does the core language need to be extended to incorporate this? const at = (arr, i) => i >= 0 ? arr[i] : arr[arr.length + i];
Why does the core language need to be extended to incorporate this?I had the exact same thoughts when `.includes()` was proposed to be added to the spec - it's just `.indexOf() !== -1`! - but time has proven me wrong, and I suspect it will prove us wrong about `at` as well.
I've written an `.indexOf() !== -1` check hundreds if not thousands of times, and I've gotten the conditional wrong enough times to actually need to revert a change in prod.
I have similar thoughts about .at(). Taking an element from the end of the array is ever-so-slightly error prone. Sure, you won't make a mistake this time, or the next time, but write it a hundred times, or a thousand, and I bet a bug will slip in. It's darn near impossible to get `.at(-1)` wrong, however.
Also: `[1, NaN, "hi"].indexOf(NaN)` is -1 but `.includes(NaN)` returns true as expected.
Brutal.
You need to use a transpiler (like Typescript), but at this point, there no reason to implement that in the language, a transpiler can implement the feature by simply adding the method to the prototype of the object, like this:
Array.prototype.at = function (i) { return i < 0 ? this[this.length + i] : this[i] }Plus you're probably missing a few dozen edge cases and optimizations that the native version would incorporate.
We wouldn't have been in node_modules dependency hell if they incorporated a few more things into the standard library or language.
- frameworks like react or express and extensions for the same
- meaningful libraries like axios, ramda, date-fns or qs
- transpiler/bundler enhancements like webpack loaders or babel presets
I would prefer that the JS committee focused on bringing meaningful new capabilities to node and the browser that are currently lacking, like they did with the various HTML5 libraries, fetch(), ES classes and so on, rather than providing tiny functions that aren't even providing new functionality (array indexing is easy and idiomatic in JS). If there was no opportunity cost then sure, add tiny pointless builtin functions all day long.
Those tiny little libs providing tiny little functions are likely not direct dependencies of your application, rather dependencies of a subdependency of a subdependency of a subdependency of your preferred "meaningful" library.
I... don't really see why it wouldn't? What's your logic here?
Even with all the basic functions one could hope for being brought into JS' core, there will still be tons of bizarre micro-libraries like these in the npm repository being used by developers who rely on libraries first when it comes to any given feature, because doing so is part of JS culture for the reasons I outlined before.
FWIW, I consider `at` to be similar to some of the things you consider "new capabilities". `fetch` vs `XMLHttpRequest` is fairly analogous to `at` vs `arr[i]`, and similar arguments can be made about ES6 classes over prototypal classes, etc.
> `fetch` vs `XMLHttpRequest` is fairly analogous to `at` vs `arr[i]`
If you consider all syntactic sugar to be equivalent, no matter how minor the change, then anything above a basic Turing machine implementation is fairly analogous. The problem with XHR is that the interface was really bad. The interface for arr[i] is not really bad.
Similarly, sure you can do point-free style w/ ramda's `R.add` but realistically, do you really? The fundamental game changer capability is the language's ability to do math in the first place; anything on top is arguably cherry on the cake. `at` seems uncannily similar in that regard.
Wrt something being in a 3rd party library vs stdlib, I'll generally prefer a batteries included approach in JS because module resolution is complex enough to cause difficult problems to troubleshoot (peerDeps hell, complex symlinking semantics, library duplication in bundles, core.js explosion, package manager specific breakages, etc)
We shouldn't write stuff in native code for performance... We should write the compiler to detect these and output optimized code.
const leftpad = (str, len, char = ' ') => str.length >= len ? str : (char.repeat(len - str.length) + str);
Anybody who installs a dependency instead of writing a one line function is just leaving themselves exposed for no real benefit.Providing the at function outside of the prototype chain like I did above will not incur the cost you mentioned, even in the unlikely case that such calls are the bottleneck of your application.
Plus, if array lookup calls are your bottleneck then you probably need a different data structure.
Just look at your at() function, I already spotted a bug, if a numeric string is passed: `([].length + '-1') === '0-1'`
const at = (arr, i) => {
if(!(Array.isArray(arr) && typeof i === 'number')) {
throw new Error('invalid arguments');
}
// same as before
};
you wouldn't just commit a single-line function in your code. But there are 10,000 micro-functions that could be in the core of JS. Why bother to add this, especially if it's so easy to implement? There are surely better things the JS committee could be putting their time towards, like providing functionality that is presently lacking in JS (maybe they could finally get around to advancing the pipe operator through the TC stages).This goes to show that it's NOT trivial to implement in a robust way.
To invert your argument, why would you want millions of developers to have to waste their time writing this sort of thing for such a common need?
Yes, it's clear that you could write the function correctly.
Could everyone?
What about bugs that aren't obvious? The runtime errors that result?
Why would we want to waste so much developer time and effort globally, when we can just add .at() to the language?
Having a standard lib for these sort of functions is a common pattern many languages adopt.
Yes, the full "standard libarary" you can expect to be present on any given JS VM may vary, but there's no plausible reason that e.g. at() should not work on almost any conceivable platform.
True, NodeJS runtime comes with its own «standard library» but npm has nothing to do with it.
const at = (arr, i) => i >= 0 ? arr[i] : arr[arr.length + +i]; let i = -1n;
let test = +i;
> Uncaught TypeError: can't convert BigInt to number
See this is where standard libraries shine, they consider all the pieces of the puzzle. There's no good reason to disallow bigints here.P.S: Unary plus operator is neat but this TypeError with BigInt is why I am starting to prefer the more verbose `Number(i)`.
Auditing the entire dependency tree of every library you choose is extremely arduous without proper tooling, and the tooling here has never been good (and even the more recently available better tooling is CVE-focused so won't highlight tells like package size/maintenance status/whatever other heuristics you might devise as a proxy for quality).
const leftpad = (str, len, char = ' ') => str.padStart(len, char);