17:47
<Ben Lesh>
Has there ever been discussion of adding very common functions to the standard. In particular noop and identity? Is a palatable to propose adding something like Function.noop and Function.identity to the standard, so people stop creating () => {} and x => x over and over in their libraries and codebases?
17:49
<ljharb>
yes
17:49
<ljharb>
i tried doing that early in my tc39 time, and before i even got to proposal stage nobody found it valuable. engines seem pretty good at optimizing () => {}
17:51
<Ben Lesh>
Interesting. I mean the next thing I'd ask for would be a Function.pipe but given the discussion over |> I suspect that wouldn't go over. :)
17:52
<ljharb>
unrelated to pipe, that was rejected on its own merits, let me find the link
17:52
<ljharb>
https://github.com/tc39/proposal-function-pipe-flow
17:52
<ljharb>
ah, i guess not entirely unrelated to pipe
17:58
<Ben Lesh>
Yeah, that's pretty much exactly what I'm proposing. Haha. Disappointing but not at all surprising. 😅
18:00
<Ben Lesh>
Have there been any updates to the :: bind proposal? That's been dead-ish since about 2015, I think.
18:01
<Ben Lesh>
https://github.com/tc39/proposal-bind-operator .. seems still dead.
18:04
<Ashley Claymore>
Has there ever been discussion of adding very common functions to the standard. In particular noop and identity? Is a palatable to propose adding something like Function.noop and Function.identity to the standard, so people stop creating () => {} and x => x over and over in their libraries and codebases?
We already have noop, it's just got a weird name `Function.prototype` 🫣
18:06
<bakkot>
I think if the syntax proposal dies there's at least some chance the stdlib function might come back, though tbh I kind of prefer reading chained arrows or chained calls over reading a call to pipe
18:06
<Ben Lesh>
Haha. Yeah, I used to do that trick, but i got tired of explaining it to people. Also passing it around is like noop.lol = 'wee' and everyone has fn.lol from then on. Or delete noop.call
18:12
<Ben Lesh>
Well, the current |> proposal makes me sad. I really don't like it at all... which historically means it will do well in the TC39. In fact, if you all want me to be a fortune teller, you could just point me at a proposal, and if I don't like it, it's probably going to Stage 2 minimum. If I do like it, it'll be stuck in Stage 1 forever. 😅
18:19
<Ashley Claymore>
I have a proposal idea. If your fortune telling rates are reasonable  I'll DM you 😎
18:20
<ljharb>
Have there been any updates to the :: bind proposal? That's been dead-ish since about 2015, I think.
yes! https://github.com/tc39/proposal-call-this
18:22
<Ben Lesh>
yes! https://github.com/tc39/proposal-call-this
I like it! Therefor it's dead at the next discussion. Sorry.
18:23
<ljharb>
lol
18:23
<ljharb>
there's a variant of it that tab has suggested as well
18:23
<ljharb>
fwiw i made it pretty clear at pipeline advancing to stage 2 that a requirement for going to stage 3 was something like call-this or :: being on a likely path to advancement, if that helps
18:29
<Ben Lesh>
fwiw i made it pretty clear at pipeline advancing to stage 2 that a requirement for going to stage 3 was something like call-this or :: being on a likely path to advancement, if that helps
I care more that I get something I can prepare for reasonably, and something that doesn't make code that is hitting libraries I'm responsible for more verbose (and arguably less readable). So what happens with |> at this point, I guess I don't care because I have very little use for that in anything I'm working on at the moment. ~> or the like, on the other hand ARE interesting to me, and it's plausible that RxJS and other libraries could pivot that way.
18:38
<bakkot>
I want neither of these things :(
18:38
<bakkot>
I would've been OK with pipe if there was a version which made everyone happy, but there isn't
18:39
<bakkot>
the call-this operator I am still confused why people think it's a good idea despite me being like a 98%ile user of .call
18:41
<Ben Lesh>
I'd only want call-this because pipeline is wrong, TBH. I'm looking to see if there are ways to prep libraries that compose like RxJS does for either the current pipeline proposal or call-this. Current pipeline proposal isn't something people can engineer towards right now in an ergonomic way... We might be able to with call-this though. Still experimenting for my use cases.
18:44
<ljharb>
it's a good idea because of the order being wrong with .call, and also syntax is undeniable and robust, which is pretty important for invoking functions
18:45
<bakkot>
"syntax is undeniable and robust" is important to rounds-to-0% of programs
18:47
<Kris Kowal>
For those programs (like Node.js core), the performance cost of uncurryThis is good to avoid.
18:47
<bakkot>
if you're trying to be defensive against people mutating builtins you have to run first cache all of the other standard library stuff anyway, at which point a.) your ergonomics are already shot and b.) caching call in addition is a very small burden
18:48
<bakkot>
For those programs (like Node.js core), the performance cost of uncurryThis is good to avoid.
you may be interested in https://github.com/nodejs/TSC/issues/1438
18:48
<ljharb>
it's important to a MUCH larger percentage than that, because they transitively run code they didn't author
18:49
<ljharb>
the reason node wants to remove primordials isn't because robustness doesn't matter, it's because the current approach sucks for ergonomics and perf
18:49
<ljharb>
call-this, specifically, would be a huge benefit for node, which would help quite a lot of programs.
18:49
<bakkot>
just because a program has a dependency which makes use of a particular feature doesn't mean that the feature is important to the program
18:50
<bakkot>
it may be - as it is in this case - that the dependency is using something so that it can provide a guarantee (e.g. "robust against other code on the page messing with built-ins) which the actual program doesn't care about
18:52
<Kris Kowal>
it would be odd for javascript to accept defeat as a safe sandbox language in the face of supply chain attacks when it’s the closest language to winning and the most important field to win.
18:52
<ljharb>
true. but the program also may only be able to not care about it because that guarantee is already provided without them knowing
18:52
<ljharb>
it's a really strange argument to me that because people don't yet care about robustness, the language shouldn't make it maximally easy and performant to be robust.
18:52
<bakkot>
it would be odd for javascript to accept defeat as a safe sandbox language in the face of supply chain attacks when it’s the closest language to winning and the most important field to win.
"you have to use .call" is not "accepting defeat as a safe sandbox language"
18:53
<bakkot>
it's a really strange argument to me that because people don't yet care about robustness, the language shouldn't make it maximally easy and performant to be robust.
no feature that we ever add to the language is going to cause people to write anything other than array.push, nor should it
18:53
<Kris Kowal>
you can’t use .call. You have to use uncurryThis, which frustrates optimization.
18:54
<bakkot>
"engines haven't optimized userland uncurryThis" is also not "accepting defeat as a safe sandbox language"
18:55
<Kris Kowal>
no feature that we ever add to the language is going to cause people to write anything other than array.push, nor should it
on this we agree, at least, but it doesn’t completely eliminate the need for fast call bind for some foundational code that has to run before the prototypes can be made immutable.
18:55
<Kris Kowal>
engines optimizing uncurryThis would also be an acceptable outcome.
18:55
<bakkot>
true. but the program also may only be able to not care about it because that guarantee is already provided without them knowing
they are already relying on array.push() working in their own program, so the fact that the dependency wants to be robust against people mutating Array.prototype is completely irrelevant to their program
18:56
<bakkot>
so, no. they are able to not care because it does not in fact matter in practice in almost any program.
18:56
<bakkot>
engines optimizing uncurryThis would also be an acceptable outcome.
A stdlib proposal for uncurryThis and similar would be fine by me
18:56
<bakkot>
just not syntax
18:56
<bakkot>
(wasn't there one, actually?)
18:58
<bakkot>
ah https://github.com/js-choi/proposal-function-demethodize
18:59
<ljharb>
not all programs mutate arrays.
19:00
<bakkot>
very nearly all programs are written in a style which assumes builtins are intact.
19:01
<bakkot>
as well they should.
19:01
<bakkot>
no feature we ever add to the language is going to cause people to write in a way which does not assume that, nor should it.
19:03
<Kris Kowal>
i see no argument that suggests anyone here holds the contrary position
19:03
<bakkot>

the specific claim I am defending is

"syntax is undeniable and robust" is important to rounds-to-0% of programs

19:04
<Kris Kowal>
but i for one propose that under some conditions it is both valuable and possible to not only assume they’re in tact, but to make it possible to rely on their being in tact.
19:06
<Kris Kowal>
i agree that very few existing programs rely on the immutability of shared primordials, but that’s circular. they are rare because of the economics of security, which we are in a position to adjust.
19:07
<bakkot>
I am ok with exploring adjustments which don't require people to completely change the style in which they write their programs, for sure
19:07
<bakkot>
however, that does not include the call-this proposal
19:08
<Kris Kowal>
and on that, i think you and i at least agree that a non-syntactic solution is acceptable
19:10
<Kris Kowal>
i merely disagree that the winning argument is based on the unimportance of defending language integrity in mutitenant (read: effectively all) programs
19:11
<Kris Kowal>
the winning argument is that it’s possible to achieve that goal without syntax that a minority of programs will need to use before making intrinsics immutable
19:13
<Kris Kowal>
and in some flavors, systems like airgap would prefer to accept the ergonomic cost of using a call-bind pattern pervasively instead of making intrinsics immutable.
19:13
<bakkot>
if that's the path forward you'd also need to ensure making intrinsics immutable doesn't break everything, which is... demonstrably tricky
19:14
<Kris Kowal>
for sure
19:15
<Kris Kowal>
not as bad as you’d think for specific applications, but override mistake is certainly a recurring theme in herding the ecosystem into the safe subset.
19:15
<bakkot>
at the very least it entails replacing everything with accessors, doesn't it?
19:15
<bakkot>
which is... oof
20:05
<shu>
i agree that very few existing programs rely on the immutability of shared primordials, but that’s circular. they are rare because of the economics of security, which we are in a position to adjust.
are you threatening to hack people or what
20:27
<Kris Kowal>
Notably, nothing based on classes suffers from the override mistake. So, replacing a lot of intrinsic value properties with accessors does make a lot of the problem go away. It’s far from ideal.
20:27
<bakkot>
well, doesn't suffer from the override mistake as long as you declare all your fields, anyway
20:27
<Kris Kowal>
aye.
20:37
<Kris Kowal>
I hacked a computer once. I locked my dad out of a 486 by putting an infinite loop in AUTOEXEC.BAT. And echoing out some ANSI that remapped Y and N to *. And also making the foreground color black.
21:42
<Mathieu Hofman>
at the very least it entails replacing everything with accessors, doesn't it?
I still believe we can arrive at an override mistake fix, at least for the use case that matters of a frozen prototype chain, that does not require making everything in those prototype chains accessors. One option would be to record the frozen choice on the object (like an integrity level), and fallback to the set on receiver if the prototype object is in that state. We don't even need to conflate the current frozen state with this new state, which could be an "extra-frozen" level instead.
21:51
<bakkot>
right, yes, fixing the override mistake is also an option
22:30
<voidhedron>
What exactly is "the override mistake"? Trying to search it on google even adding "javascript" as keyword only yields irrelevant results
22:32
<ljharb>
voidhedron: 'use strict'; var o = ({ __proto__: Object.freeze({ foo: false }) }); o.foo = true; it throws, instead of defining an own property on o
22:32
<Kris Kowal>
There’s a mention here https://exploringjs.com/deep-js/ch_property-assignment-vs-definition.html
22:41
<bakkot>
https://github.com/tc39/how-we-work/blob/c96099d8ab460b933bd80d65b8b4c6a05ee0c791/terminology.md#override-mistake
22:53
<voidhedron>
voidhedron: 'use strict'; var o = ({ __proto__: Object.freeze({ foo: false }) }); o.foo = true; it throws, instead of defining an own property on o
Ah interesting, I think I may have accidentally ran myself into that once or twice
22:56
<voidhedron>
that's an understatement actually, looking back on my code now
22:58
<voidhedron>
I actually enjoy using nodejs with their --frozen-intrinsics flag for personal projects, so a lot of my code is written to handle that but I've just never recognized it as a well known pattern (mainly because it's caused by an experimental flag which I assume very few use)
22:58
<ljharb>
it also breaks a surprising number of packages, due to the override mistake (often transitive deps, not because lots of code breaks from it)
23:01
<voidhedron>
Yeah I'm aware, it may or not be related to the fact that I am also very packagephobic, at least at runtime, devDependencies all good, I pull in tsc and stuff whatever, but runtime deps I avoid as much as possible and always thoroughly review any I pull in, and when I do I only use zero or low dependency ones so I can avoid issues related to that and other things :P
23:02
<voidhedron>
I also often just copy the specific parts of a package I actually want directly into my code so I can adapt it into my hardened-JS-style I prefer
23:03
<voidhedron>
I actually have a helper function I created that I guess solves the "override mistake" although I didn't realize it was known as that when I did it
23:09
<voidhedron>

it's not that complex:

function setOwnKey(o, key, value) {
  const p = Object.getPrototypeOf(o);
  Object.setPrototypeOf(o, null);
  o[key] = value;
  Object.setPrototypeOf(o, p);
}

it works for anything as long as o itself is not frozen, only its prototype

23:10
<voidhedron>
has TC39 ever considered just adding a function like this to solve the "mistake"?
23:10
<voidhedron>
like Reflect.setOwnKey
23:11
<shu>
opt-in fixes won't fix the mistake; the mistake is that it proliferates in shipped code that's not updated
23:11
<shu>
you can already opt-in to use define instead of set semantics to work around
23:12
<voidhedron>
ah I see, fair enough
23:13
<bakkot>
and then you don't have to change the prototype of your thing
23:13
<bakkot>
which you generally want to avoid for optimization reasons