[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)