[HN Gopher] Stage 3 Proposal: Array.prototype.at
       ___________________________________________________________________
        
       Stage 3 Proposal: Array.prototype.at
        
       Author : bpierre
       Score  : 54 points
       Date   : 2021-06-02 11:24 UTC (11 hours ago)
        
 (HTM) web link (tc39.es)
 (TXT) w3m dump (tc39.es)
        
       | trinovantes wrote:
       | This is going to confuse C++ developers where vector::at()
       | explicitly throws exceptions on out of bounds access
       | 
       | But I guess the intersect between C++/JS developers is too small
       | to care
        
         | yoz-y wrote:
         | As one of those c++/js developers I'd just say that I do not
         | map concepts from one language to another because it rarely
         | works anyways.
        
       | ezekg wrote:
       | Am I reading this correctly -- it's an alias for arr[i] and
       | str[i]? I know languages like Ruby have arr.at(i), but why?
        
         | twoodfin wrote:
         | A quick read suggests that it adds negative indexing from the
         | end of the array.
        
           | Pxtl wrote:
           | Imho that violates the principle of least astonishment - that
           | "at" would have such different behavior from "[]" for
           | negative numbers.
        
             | [deleted]
        
             | ZephyrBlu wrote:
             | That's the whole point of this though... Currently you
             | can't use negative indexes, but this would make them
             | usable.
        
               | Pxtl wrote:
               | Oh, I'd assumed main point was to provide a composable
               | function.
        
         | pininja wrote:
         | Accessing negative indexes currently returns undefined. This
         | adds support for indexing from the end of an array with
         | negative numbers.
        
           | franciscop wrote:
           | This works, but not the way you'd think:
           | const arr = [];         arr[-1] = 'Hello world';
           | console.log(arr[-1]);         // Hello world
           | 
           | Instead of using the negative index, it stringifies the "-1"
           | and uses it as the key of an object both when writing and
           | reading. Thus, arr.length still remains 0
        
         | maweki wrote:
         | It's a function object then.
        
         | nvartolomei wrote:
         | Proposal hosted on GitHub explains the reasoning behind it
         | https://github.com/tc39/proposal-relative-indexing-method
        
         | antris wrote:
         | In addition to negative index support, a function is more
         | easily composable e.g. converting a list of indices to a list
         | of objects: `indices.map(myObjectArr.at)`
         | 
         | I've lost count on how many times I've wrote this function
         | manually.
        
           | inbx0 wrote:
           | That will break with
           | 
           | > Uncaught TypeError: Cannot convert undefined or null to
           | object
           | 
           | because `myObjectArr.at` doesn't bind `this` to
           | `myObjectArr`. When the internals of `map` call the `at`
           | function, `this` is just `undefined` instead of the original
           | array and it'll throw.
           | 
           | Luckily Array.prototype.map takes a second argument just for
           | this purpose                   indices.map(myObjectArr.at,
           | myObjectArr)
        
             | antris wrote:
             | Oh wow, I had to try it to make sure. I can't believe how
             | broken the fundamentals of JS are.
             | 
             | There should really be a whole new standard library made
             | from ground up without `this`, mutability and all the other
             | legacy stuff.
        
               | [deleted]
        
           | joppy wrote:
           | The alternative being the pretty-much-just-as-short
           | indices.map(i => myObjectArr[i])?
        
             | antris wrote:
             | Composability is not about syntax but being able to express
             | code as values. You can have complex behaviors from pure
             | functions that are guaranteed to work and can be recomposed
             | into more and more complex structures.
             | 
             | It's not a big thing of course with such a simple example,
             | but just try to program without defining a single function
             | and you'll see how tiresome it soon begins to write
             | everything out manually.
        
           | bidirectional wrote:
           | > `indices.map(myObjectArr.at)`
           | 
           | That works in this case, but eta-reduction is not generally
           | safe in Javascript due to the variadic nature of many
           | functions, so I wouldn't recommend it in production code. For
           | example `indices.forEach(console.log)` does not work as one
           | would expect.
        
             | antris wrote:
             | Better a function that works in some cases than not having
             | a function at all. Also, by using TypeScript definitions
             | you pretty much always know what's coming in and going out
             | and VS Code will yell at you if you're trying to do
             | something stupid.
        
               | benjaminjackman wrote:
               | TypeScript definitions don't block and VS Code does not
               | warn for `indices.forEach(console.log)`
               | 
               | When using eta-reduction in Javascript both functions and
               | all their (optional) arguments have to be known by the
               | programmer and future programmers, instead of needing to
               | know only the argument-slots being used by (x,y,...) =>
               | ...
               | 
               | It also defends / insulates against more parameters being
               | added in the future.
               | 
               | Additionally, the way `this` in javascript works (or
               | doesn't for a lot of callbacks) also pushes against using
               | eta-reduction.
        
               | antris wrote:
               | >TypeScript definitions don't block and VS Code does not
               | warn for `indices.forEach(console.log)`
               | 
               | Sure, it's a valid way of logging all the arguments that
               | pass through forEach. I don't see a problem here?
               | 
               | >When using eta-reduction in Javascript both functions
               | and all their (optional) arguments have to be known by
               | the programmer and future programmers, instead of needing
               | to know only the argument-slots being used by (x,y,...)
               | => ...
               | 
               | My VSCode setup shows all arguments of functions
               | automatically. Also, I always avoid optional arguments in
               | my code and writing functions that take in a variable
               | amount of arguments or arguments of different types. I
               | always refactor these out of my codebase.
               | 
               | >Additionally, the way `this` in javascript works (or
               | doesn't for a lot of callbacks) also pushes against using
               | eta-reduction.
               | 
               | `this` is another smell that I always avoid using in my
               | codebase, and refactor code that uses it to work without
               | `this`. I thought `this` being harmful is common
               | knowledge?
        
               | jakelazaroff wrote:
               | That won't work in this case. TypeScript won't yell at
               | you if you pass a function that doesn't use all its
               | arguments. If a second number argument is ever added to
               | `at`, your code using it this way will break and
               | TypeScript will not warn you.
               | 
               | This blog post explains why what you're proposing is
               | dangerous: https://jakearchibald.com/2021/function-
               | callback-risks/#type...
        
               | antris wrote:
               | I guess I'm then somehow doing subconscious mental
               | gymnastics to prevent this, because me and several of my
               | colleagues have coded like this for years and it hasn't
               | been a problem even once.
        
               | e1g wrote:
               | A function that works in some cases will be a nightmare
               | to debug. The pattern of `indices.map(myObjectArr.at)` is
               | discouraged in JS because it often fails in unexpected
               | ways. For example -
               | ["1","2"].map(parseFloat) // works as expected
               | ["1","2"].map(parseInt)   // nope
        
               | antris wrote:
               | I've learned ages ago that parseInt cannot be used like
               | this, so it's not a problem for me, but I thought linters
               | already take care of this case? Also I wasn't talking
               | about using parseInt, a broken function like this so I'm
               | not sure what the quirks of old, widely known bad parts
               | of Javascript have to do with using functions as
               | arguments, which is one of the most powerful features of
               | the language.
        
       | dlojudice wrote:
       | JS urgently needs support for decimals [1] and thus be able to
       | enter sectors such as scientific and financial.
       | 
       | V8 + dynamic language + better math support = perfect environment
       | for many applications out there
       | 
       | [1] https://github.com/tc39/proposal-decimal
        
         | Aardwolf wrote:
         | For financial makes sense, but science should be independent of
         | numerical base?
        
           | ihuman wrote:
           | I think the issue isn't the base, but that Javascript stores
           | all numbers as 64-bit floats.
        
             | dragonwriter wrote:
             | The decimal proposal is a vague enough that it is unclear
             | if it would improve on that; _if_ it was arbitrary-
             | precision decimals, that would be an improvement. If it is
             | limited precision but better than Number (seems unlikely),
             | it would be an improvement. If it is limited precision but
             | not better range /precision than Number, just decimal
             | rather than binary floating point, its probably not an
             | improvement. The proposal is vague enough that any of those
             | would fit.
        
             | dfabulich wrote:
             | JS has BigInt now. You can kinda fake BigDecimal with it,
             | but none of the built-in operators will work.
        
               | runarberg wrote:
               | How do you fake BigDecimal with BigInt? My immediate
               | intuition would have a 3-tuple ( _a_ , _b_ , _c_ ) which
               | would construct the decimal with _a_ representing the
               | numbers before the decimal separator, _b_ the number of
               | zeroes immediately after the decimal separator, and _c_
               | the numbers after the zeroes. e.g. 1.000054 would be
               | represented as `[1n, 4n, 54n]` and 3.14159 as `[3n, 0n,
               | 14159n]`.
               | 
               | Is there a better way?
        
               | lbussell wrote:
               | What about a 2-tuple with two numbers, one being the
               | BigInt and one being the exponent. So 1.000054 would be
               | (1000054, -6) = 1000054*10^(-6).
               | 
               | Yours is probably more space efficient though.
        
         | cogman10 wrote:
         | Couldn't that be done with WASM today? It looks like a few
         | people have managed to build GMP targeting WASM.
         | 
         | You might miss out on some SIMD operations, but you'd be able
         | to do 90% of what you'd want with scientific calcs.
         | (admittedly, it'd be nice if this were part of the language).
        
           | diamond_hands wrote:
           | There's still a ton of overhead for WASM and it's not first
           | class. Using WASM is a lot like using C code in python. It's
           | still nice to have features as first class citizens :)
        
             | schwartzworld wrote:
             | Isn't most python just stringing together c and Fortran
             | libraries that expose a python interface?
        
         | runarberg wrote:
         | Honest (possibly stupid) question: Do people working on
         | statistical and probability application never need a numeric
         | type optimized for probability values (i.e. values between 0
         | and 1 that can get _really_ close to either; for example the
         | really almost certain value of _p_ = 1 - 10^-13)? In the same
         | way that financial application needs a decimal type?
         | 
         | I've only worked on probability applications at a surface level
         | for a tiny bit and never really needed it, but I kept wondering
         | whether there were such a numeric types, and if not, what
         | people did if they needed it.
        
           | joppy wrote:
           | Log probabilities are used a bit for this, and most numeric
           | packages (numpy for instance) have special functions for
           | computing log(1+x) which are more accurate when x is tiny.
        
       | sfinx wrote:
       | If I understand this correctly it is to add negative index
       | support to arrays. How will findIndex work when this is
       | introduced? It currently uses -1 as a return value when no
       | element satisfies the testing function.
        
         | jakelazaroff wrote:
         | You can't have a negative array index. Passing a negative
         | number will just make this function count backwards instead of
         | forwards.
         | 
         | [1, 2, 3, 4].at(0) === 1
         | 
         | [1, 2, 3, 4].at(1) === 2
         | 
         | [1, 2, 3, 4].at(-1) === 4
         | 
         | findIndex's behavior is unchanged.
        
         | almost wrote:
         | It's not adding negative indexes, a negative number will index
         | from the end.
         | 
         | So [0, 1, 2, 3].at(-2) === 2
        
           | onion2k wrote:
           | That would mean getting the last element of the array would
           | be [0,1,2,3].at(-1).
           | 
           | I don't like that very much.
           | 
           | Mind you, I don't like the idea of using [0,1,2,3].at(-0)
           | either...
        
             | zodiakzz wrote:
             | Good thing we don't have to stagnate progress just because
             | what we have will never be perfect.
        
             | jakelazaroff wrote:
             | Don't think of it as counting from the end of the array --
             | think of it as counting in reverse from the 0th element.
             | .at(1) gets the next element (index 1) while .at(-1) loops
             | around and gets the "previous" element (index 3, in this
             | case).
             | 
             | Or, if it's more intuitive, you can think of the array
             | index as an unsigned integer where the max is equal to the
             | length of the array. If you try to assign -1 to a uint8,
             | the result will be 255 -- the highest possible value (the
             | last index).
        
         | pedrow wrote:
         | Python also uses negative indexes in this way, see
         | https://docs.python.org/3/library/stdtypes.html#common-seque...
        
         | onion2k wrote:
         | Array.prototype.at would only ever return the value of
         | something in the array at the index requested (or undefined).
         | It'd accept a negative offset, but that's not the index of the
         | thing you're looking for; it's an offset from one end of the
         | array.
        
       | Phenix88be wrote:
       | So instead of fixing the language and allow to use array[-1],
       | they add an other way to access array element. This is why I
       | don't like JavaScript, instead of fixing feature, they add new
       | feature to fix previous feature.
        
         | JoBrad wrote:
         | It is consistent with slice, though. Neither changes the
         | implementation of the array, they just provide ergonomic
         | benefit to the developer.
        
         | Spivak wrote:
         | The problem with JS language development is the mountain of
         | code that it would break if you do anything except append
         | features.                   array[-1] = "foo"
         | 
         | This already works in JS but doesn't do what you expect and
         | just assigns the property.
        
           | kevincox wrote:
           | To be clear this is equivalent to array["-1"] (unless you do
           | horrible things overriding the built in types). Since arrays
           | are "just" objects in JavaScript it is completely valid to
           | add a property called "-1" to it.
        
           | cogman10 wrote:
           | Javascript array indexing is a MESS. This
           | array["foo"] = "bar"
           | 
           | is valid javascript.
        
             | Osiris wrote:
             | Why does this make it a mess? Array already has a bunch of
             | properties that aren't elements in the Array that come from
             | the prototype, like join and slice. Your example is just
             | adding a custom property to the array.
        
               | cogman10 wrote:
               | Because in most other languages, an array is an
               | enumeration of values. That's it.
               | 
               | In Javascript, arrays are actually dictionaries. But not
               | full dictionaries, rather just dictionaries that can have
               | either a string or numeric key.
               | 
               | It's messy because an array in javascript isn't just "an
               | array" it's this mismesh of features that are unexpected
               | to a new-to-javascript developer.
               | 
               | Unexpected is the enemy of readable code.
        
               | gsnedders wrote:
               | No, arrays are just objects with a magic "length"
               | property (technically: a special [[DefineOwnProperty]]
               | internal method which sometimes also mutates "length").
               | Like objects, they only support strings as keys.
               | 
               | c.f. https://tc39.es/ecma262/#sec-array-exotic-objects
        
             | londons_explore wrote:
             | array["at"] = "lunchtime";
             | 
             | Is also valid javascript... And will break functionality in
             | this proposal!
        
               | runarberg wrote:
               | I think this is the point of the stage 3 proposal.
               | 
               | Browser makers start implementing the feature and
               | releasing it in the development and beta versions of
               | their browsers. Then if the users of the experimental
               | features start noticing that webpage break, the proposal
               | will get an update.
               | 
               | If I remember correctly, this exact thing happened to
               | `Array.prototype.flatten` which got renamed to
               | `Array.prototype.flat` after it was realized that the
               | former broke a lot of legacy webpages (and after a long
               | discussion of `Array.prototype.smoosh`[1])
               | 
               | 1: https://developers.google.com/web/updates/2018/03/smoo
               | shgate
        
         | wereHamster wrote:
         | There is existing code out there which relies on negative
         | indexes to return undefined. Or relies on being able to assign
         | items to negative indexes and then retrieve them, this is
         | perfectly valid code: `a=[];a[-1]=42;console.log('the answer
         | is',a[-1])`. The web tries really hard to be backwards
         | compatible and not break existing code.
        
           | eknkc wrote:
           | Maybe we should re utilize the "use strict"; type of
           | metadata. Something like "use es2021" to enable negative
           | indexes etc.
        
             | JoBrad wrote:
             | I expect what we'll end up with is languages like TS
             | supporting a flag to convert all/most index lookups into
             | .at() notation. Or maybe it'll just be an eslint flag.
             | 
             | I absolutely agree that some metadata at the top of a
             | module enabling behavior like this would be ideal.
        
             | lhorie wrote:
             | IIRC Google actually experimented with the idea of an even
             | stricter mode in V8 at some point but dropped it when it
             | didn't materialize the perf gains they were hoping for.
             | 
             | From a spec perspective, ES6 modules were a good milestone
             | to "flip the switch" over to strict mode by default, but
             | even with that being a fairly successful strategy (IMHO),
             | it still left some nasty corner cases around the language
             | (namely, there are now two distinct top level grammars,
             | which led to the whole .mjs bikeshedding rabbit hole)
        
             | Slackwise wrote:
             | I've been thinking this for _ages_.
             | 
             | We need more special contextual comments to change a file
             | or scope to behave better so we can move forward and scrape
             | away all the bad legacy of JS.
        
               | dragonwriter wrote:
               | > We need more special contextual comments to change a
               | file or scope to behave better so we can move forward and
               | scrape away all the bad legacy of JS.
               | 
               | I don't think making the JS world into even more of a
               | "set of subtly different languages that look mostly
               | similar" is necessarily a solution so much as an extra
               | problem.
        
             | dangoor wrote:
             | TC39 explicitly rejected this sort of approach a few years
             | ago, because of the unpleasant way it would fork the web.
             | They _did_ automatically clean up some behavior in a module
             | context when you knew you were using a modern JS engine,
             | but they kept that to a minimum.
             | 
             | Unfortunately, I couldn't find any links to articles
             | written at the time about this, but they definitely did
             | consider "use" options or script type="es2021" kinds of
             | options.
        
           | kreetx wrote:
           | How about deprecating that for a few years then? Doesn't seem
           | good to keep the behavior, given that it will also be
           | confusing in the future.
           | 
           | But perhaps we just don't know enough, and they will add the
           | `at`, and at some point actually do bind `arr[index]` to use
           | the implementation of that function?
        
             | rand_r wrote:
             | The web as a platform is the most elaborate and epic
             | showcase at not breaking backwards compatibility in the
             | entire history of computing.
             | 
             | In the face of disasters like Python 2->3 and Apple M1 macs
             | no longer being able to play Starcraft Remastered, the web
             | is an aspirational beacon.
             | 
             | Let's keep it going.
        
               | Fire-Dragon-DoL wrote:
               | Isn't Windows even more epic?
        
               | rand_r wrote:
               | You might well be right! Would be fun to see them go
               | head-to-head over the title.
        
               | dmitriid wrote:
               | Windows is _very_ epic, but they did break compatibility
               | a few times: the new driver model since Windows 7 (?) for
               | example.
               | 
               | The Web probably has a longer history of not breaking
               | things, but also has a smaller feature set to keep track
               | of than Windows.
               | 
               | All in all, very hard to compare. But both undoubtedly
               | epic.
        
               | the_only_law wrote:
               | For all the (often deserved) hate Windows gets, in
               | particular the user space API's, I still find the chaos
               | incredibly exciting and an invitation to hack together
               | all sorts of strange things in strange manners. I'm
               | sometimes surprised by the levels of backwards
               | compatibility and the "obsolete" technologies that still
               | work fine.
        
             | machello13 wrote:
             | How would you deprecate it? There's tons of browsers and JS
             | runtimes out there and they all adopt features at different
             | speeds. Undoubtedly some browsers would never adopt the new
             | feature, which means websites will simply break, and the
             | web will become even more fragmented than it already is.
        
             | jffry wrote:
             | There's a large body of existing code out there, some of
             | which might rely on the current behavior but never be
             | updated. I doubt any length of deprecation period would
             | solve this issue.
             | 
             | Instead, adding .at() allows having the new feature now,
             | and in a way that's possible to polyfill for backwards
             | compatibility.
        
         | playpause wrote:
         | New features are added to JavaScript very carefully to avoid
         | breaking existing code on the web. The downside is you often
         | end up with multiple ways to do the same thing, but there are
         | ways to mitigate this, like using a linter to enforce using a
         | modern subset of the language.
        
           | jasonzemos wrote:
           | That's starting to sound an awful lot more like C++.
        
             | petalmind wrote:
             | It's not surprising given that JavaScript was designed and
             | deployed world-wide by C++ developers.
        
             | cxr wrote:
             | No, even then, they're fundamentally different.
             | 
             | An organization can go through and update its C++, because
             | ultimately they're distributing binaries (or doing
             | everything internally and not distributing anything at
             | all).
             | 
             | Web "pages" aren't called that for no good reason. If in
             | 2005 you bought a novel, or some punk writer-artist's
             | printed pamphlet, and now you can't read it because in the
             | meantime some engineers changed a spec somewhere, then that
             | would be a failure, not just in the small, but on a
             | societal level. _Just rev the language_ is something that
             | people who spend 40+ hours in an IDE or programmer 's text
             | editor think up when they're used to dealing in SDKs and
             | perpetually changing interdependencies and fixing them and
             | getting paid handsomely for it. But that's not what the Web
             | is. The Web is the infrastructure for handling humanity's
             | publishing needs indefinitely.
             | 
             | To rely upon another observation:
             | 
             | "[This] is software design on the scale of decades: every
             | detail is intended to promote software longevity and
             | independent evolution. Many of the constraints are directly
             | opposed to short-term efficiency. Unfortunately, people are
             | fairly good at short-term design, and usually awful at
             | long-term design. Most don't think they need to design past
             | the current release."
             | 
             | https://roy.gbiv.com/untangled/2008/rest-apis-must-be-
             | hypert...
        
               | londons_explore wrote:
               | Your post sounds good... Until you realise that nearly
               | any nontrivial web page from 10+ years ago is broken
               | today...
               | 
               | No Flash... Iframes don't work properly anymore... HTTPS
               | servers from 10 years ago are unsupported by todays
               | browsers... Most of the IE hacks no longer work (remember
               | progid:DXImageTransform?)... Any images/resources hosted
               | elsewhere are likely now nonexistent...
               | 
               | Plenty of web features have been introduced and then
               | dropped just a few years later. Backwards compatibility
               | is great... But if it's practically broken anyway, I
               | think there is a good argument for breaking it further.
               | People who need to read an old page will probably need to
               | use IE6 in a VM anyway.
        
               | cxr wrote:
               | The problem with this argument is that it demands we
               | apply a false equivalence. The key word in your comment:
               | 
               | > hacks
               | 
               | Flash was not standardized. Same with IE's proprietary
               | recommendations (and Mozilla's for that matter--XUL is
               | proprietary, even though people often use "proprietary"
               | as an antonym for "open source"). Most of the "web
               | features" that people have in mind are in the same boat:
               | experimental and draft-level proposals that eventually
               | fall by the wayside for one reason or another. The Web is
               | actually the single most successful attempt at a vendor-
               | neutral, stable platform that exists. It's why we're
               | having this conversation now.
               | 
               | The argument is that, because some people did something
               | hacky or bleeding edge and then bled from it, then
               | there's no real point in any amount of stability, so we
               | should punish _everyone_. What a double whammy that would
               | make for! First, you spend all your time taking care to
               | do things correctly, so you pay the penalty inherent in
               | that--what with moving more slowly than all those around
               | you--and then someone decides,  "ah, nevermind screw the
               | whole thing", doubles back on the original offer and then
               | breaks your shit? I can't say I'm able to abide by that.
               | Imagine all your friends getting drivers licenses and
               | receiving a bunch of speeding tickets for their
               | recklessness, then one day you get pulled over and
               | ticketed, too, regardless of the fact that you weren't
               | speeding.
        
               | runarberg wrote:
               | > nearly any nontrivial web page from 10+ years ago is
               | broken today
               | 
               | Can you provide some examples? In my experience broken
               | 10+ year old websites is the exception, not the rule. And
               | most of the exception is because flash (which has a
               | workaround; plus most popular flash websites have been
               | ported).
        
             | [deleted]
        
         | kevingadd wrote:
         | Adding this wouldn't be backwards compatible, so it can't be
         | done. Simple as that. It's not broken, either - it just doesn't
         | do the thing you want.
        
       | beaconstudios wrote:
       | const at = (arr, i) => i >= 0 ? arr[i] : arr[arr.length + i];
       | 
       | Why does the core language need to be extended to incorporate
       | this?
        
         | Cthulhu_ wrote:
         | Because at some point someone will - and probably has - make a
         | library out of this, adding yet one more to the tens of
         | thousands of files that my cruddy server can't handle already
         | because of the sheer quantity.
         | 
         | 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.
        
           | londons_explore wrote:
           | > optimizations that the native version would incorporate
           | 
           | We shouldn't write stuff in native code for performance... We
           | should write the compiler to _detect_ these and output
           | optimized code.
        
             | ihuman wrote:
             | By "native version", I think that Cthulhu meant building
             | "at" into the JS runtime, not writing "at" as a C extension
             | and compiling it into native code.
        
           | beaconstudios wrote:
           | in my experience, the vast majority of node modules I have
           | installed don't provide these tiny little functions, but are:
           | 
           | - 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.
        
             | lucideer wrote:
             | You seem to be garnering a lot of downvotes without replies
             | so I'll bite: it sounds from your comment like you've never
             | looked into the subdependency tree of those frameworks and
             | meaningful libraries that you list (which seems like it
             | would be hard to miss tbh for anyone that's ever opened up
             | the node_modules directory).
             | 
             | 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.
        
               | beaconstudios wrote:
               | I'm aware of that. Unfortunately that's always going to
               | be the case that some people who write libraries you
               | depend on indirectly are not very good at programming and
               | lean heavily on other dependencies to provide basic
               | functionality. That will be the case regardless of how
               | all-encompassing the stdlib is, and is entirely dependent
               | on the culture of practice of the language you're using.
               | JS is both beginner-friendly and the culture is focused
               | on personal marketability, so you're going to get a lot
               | of beginners land-rushing to put out basic libraries that
               | don't do anything to cater to other beginners, in order
               | to put the number of stars/npm downloads on their blog or
               | CV. That's not going to change with the number of new
               | core features.
        
               | lucideer wrote:
               | > _That 's not going to change with the number of new
               | core features._
               | 
               | I... don't really see why it wouldn't? What's your logic
               | here?
        
               | beaconstudios wrote:
               | A famous example: the is-odd and is-even libraries. It's
               | not the kind of function that would be appropriate for a
               | stdlib in my opinion, and yet developers who presumably
               | don't know about the modulo operator incorporate these
               | libraries into their projects at a high enough rate to
               | engender 700,000/week of downloads.
               | 
               | 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.
        
             | lhorie wrote:
             | ramda and date-fns are full of little such functions... The
             | fact that util packs like these and lodash exist is a sign
             | that Javascript's stdlib lacks mechanisms to deal with
             | various common patterns.
             | 
             | 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.
        
               | beaconstudios wrote:
               | ramda is an immutable library - javascript is immutable.
               | Some functions of date-fns could probably be part of the
               | core, and in fact that's one of the areas I wish the JS
               | WG would focus on as Date is just not a very useful
               | class.
               | 
               | > `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.
        
               | lhorie wrote:
               | I mean it in the opposite sense, actually (that
               | XMLHttpRequest - or more precisely, Microsoft's original
               | version of it - was a leap forward, whereas
               | fetch/axios/friends are, for the most part, merely a
               | convenience over now established capabilities)
               | 
               | 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)
        
         | zodiakzz wrote:
         | Just Google "left-pad" to know why. I think .at() also doesn't
         | have to look up the entire prototype chain so it has
         | performance benefits as well.
        
           | beaconstudios wrote:
           | 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.
        
             | lucideer wrote:
             | You're assuming this is a decision available to each app
             | developer. In fact these dependencies are usually chosen by
             | the developer of a library that's a dependency of a
             | dependency of a dependency of a dependency of a library you
             | choose as an app developer.
             | 
             | 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).
        
             | zodiakzz wrote:
             | Reinventing the wheel is error prone. Noone wants to bloat
             | their code/time with unit tests for all these utility
             | methods.
             | 
             | Just look at your at() function, I already spotted a bug,
             | if a numeric string is passed: `([].length + '-1') ===
             | '0-1'`
        
               | beaconstudios wrote:
               | yes that is obvious - my point was that the functionality
               | is minimal. with guards:                   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).
        
               | Osiris wrote:
               | Your number guard is insufficient. NaN, infinity, 2.23
               | are all Number but not supported values for the function.
               | 
               | This goes to show that it's NOT trivial to implement in a
               | robust way.
        
               | lhorie wrote:
               | If we're going to nitpick, those are actually all valid
               | values for `arr[i]`... (though, to be fair, they don't
               | exactly do what one might necessarily expect)
        
               | beaconstudios wrote:
               | It is trivial. It requires a few more lines than my
               | example, but my example was intended to show the core use
               | case. All I'm getting in replies is nitpicking about my
               | example case... Can't you just assume when reading that I
               | know how to write some simple guard statements? It's
               | hardly rocket science.
        
               | chrismorgan wrote:
               | Quite incidentally, this is fixed with the addition of
               | one character:                   const at = (arr, i) => i
               | >= 0 ? arr[i] : arr[arr.length + +i];
        
               | zodiakzz wrote:
               | Nit: it throws if you wanna use a negative bigint as `i`
               | hehehe :(                 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)`.
        
               | maest wrote:
               | > Reinventing the wheel is error prone.
               | 
               | Having a standard lib for these sort of functions is a
               | common pattern many languages adopt.
        
               | MsMowz wrote:
               | Isn't that really a pattern that the runtime adopts (i.e.
               | not the language itself)? For ES, the libraries are
               | dependent on the runtime environment; for browsers, there
               | are the web APIs, and for Node, there's npm. I'm not sure
               | how you could have anything more standard given the
               | nature of things.
        
               | Quekid5 wrote:
               | This might be just a few levels of people talking past
               | each other, but just in case:
               | 
               | 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.
        
               | Osiris wrote:
               | Their example does no argument validation. It doesn't
               | check that arr is array, or that i is an integer, etc.
               | The spec actually addresses the argument validation.
        
             | Aachen wrote:
             | I agree that dependency hell is a problem, but I don't
             | agree that reinventing the wheel is better. Including
             | things a _lot_ of developers will need in the language is
             | probably the best way to approach things like left_pad, at
             | least given these three options (reinvent, third-party,
             | language inclusion).
        
         | johnfn wrote:
         | Subtle readability improvements on patterns that see extensive
         | use actually make a difference.
         | 
         | 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.
        
           | beaconstudios wrote:
           | That's actually a pretty reasonable argument, the 'length -
           | N' form is actually quite prone to off-by-one errors so .at
           | might help there.
        
         | jahewson wrote:
         | Array parameter should be last, surely? Or why not extend the
         | prototype? If only we had some way to standardise such
         | decisions...
        
         | cphoover wrote:
         | +1
        
       | [deleted]
        
       | pedrow wrote:
       | In the proposal text, what's the meaning of the '?' and '!' - for
       | example in "Let O be ? ToObject(this value)"
        
         | IainIreland wrote:
         | Roughly speaking, '?' means that the operation might throw an
         | exception, which should be propagated if thrown, and '!' means
         | that the operation should never fail. (In Rust terms, '?
         | ToObject(this value)" -> "ToObject(thisValue)?", and "!
         | ToObject(this value)" -> "ToObject(thisValue).unwrap()".)
         | 
         | See: https://tc39.es/ecma262/multipage/notational-
         | conventions.htm...
        
       | 11235813213455 wrote:
       | This will be handy for a multitude of string libs, for example
       | string diffing (fast myers diff, ...)
        
       ___________________________________________________________________
       (page generated 2021-06-02 23:02 UTC)