00:15
<jschoi>
In the spec, is there a way to split an abstract List into a first element and another List of the other elements?
00:16
<jschoi>
“Let «first, ...rest» be list”…
00:16
<bakkot>
Nope
00:18
<jschoi>
I’ll just say, “Let rest be the List of all elements of list except its first.”
00:20
<bakkot>
If you own the list, you could just mutate it
00:21
<jschoi>
Well, how would I express that in spec language?
00:21
<jschoi>
It’d still be prose, right?
00:21
<bakkot>
i. Let r be the first element of remaining. ii. Remove the first element from remaining.
00:21
<jschoi>
Ah…
00:21
<bakkot>
or
00:21
<bakkot>
ii. Let kValue be the first element of values and remove that element from values.
00:21
<jschoi>
Nice. Thank you!
00:22
<bakkot>
Which thing are you writing that needs this? For bigint math I'd think you could just copy the Number ones
00:23
<jschoi>
Math.hypot. Killing Math.bigHypot and merging its behavior into hypot.
00:23
<jschoi>
Dispatching on the type of the first argument.
00:24
<bakkot>
Math.hypot just iterates over the list; that seems better than splitting it
00:24
<jschoi>
Well, it needs to coerce the rest of the arguments based on the first argument’s type, though.
00:28
<jschoi>
https://github.com/js-choi/proposal-bigint-math/commit/b5ece4e1543c35375f13f02653c0a7119ed0c495
00:29
<bakkot>

Yeah but you don't need to take the tail of the list for that.

I'd do something like

1. If _args_ is empty, return +0𝔽.
1. If Type(_args_[0]) is BigInt, let _isBigInt_ be *true*.
1. Else, let _isBigInt_ be *false*.
1. For each element _arg_ of _args_, do
  1. If _isBigInt_ is *true*, then let _n_ be ? ToBigInt(_arg_)
  1. Else, let _n_ be ? ToNumber(_arg_).

etc

00:29
<bakkot>
there's other ways you can write it but none of them obviously require you to construct the list-except-head
00:29
<bakkot>
just to peek at the head to determine which coercer to use
00:31
<jschoi>
Wouldn’t that cause an unnecessary call to ToBigInt or ToNumber for the first element?
00:31
<bakkot>
Type() does not perform coercion, no
00:32
<bakkot>
Though, I guess you probably want ToNumeric?
00:32
<jschoi>
I mean ToBigInt, though. It’s calling ToBigInt on args[0] unnecessarily.
00:32
<bakkot>
Yeah but that's unobservable
00:32
<jschoi>
Oh, yeah, right, ugh, I forgot that I need to call ToNumeric on the first.
00:32
<jschoi>
If we’re fine with unobservable redundant calls the spec, I can change it.
00:33
<bakkot>
If that makes the algorithm easier to read, absolutely.
00:40
<jschoi>
https://github.com/js-choi/proposal-bigint-math/commit/32152ba671e6b94e9912139db5b3a31e35ad9021
00:40
<jschoi>
Thanks for the help, bakkot!
00:42
<jschoi>
…Though would it work with Math.hypot(Object(4n))?
00:42
<jschoi>
Wouldn’t the Type(args[0]) return Object?
00:43
<bakkot>
Right, that's why I suggested ToNumeric
00:43
<jschoi>
Ah, ah.
00:45
<jschoi>
So we’re fine with just replacing it with Type(ToNumeric(args[0])), because the extra coercion is invisible to the user.
00:45
<bakkot>
Well, no, that ends up being visible, unfortunately
00:45
<jschoi>
Ah…
00:46
<bakkot>
So you do probably want to pop the list after all, I'm afraid
00:46
<bakkot>
I hadn't thought through the fact that you'd want to ToNumeric before doing the Type
00:46
<jschoi>
Thanks for the big help anyway, though. 👍️
00:54
<jschoi>
I wonder if ToPrimitive would work…
14:36
<jschoi>
Could someone familiar with TypeScript type inference explain the problem being described in https://github.com/js-choi/proposal-hack-pipes/issues/18 ? I’m not sure why the type of userOption |> map(user => user.name)(^) cannot be inferred from userOption and map.
14:37
<jschoi>
It’s just the same as map(user => user.name)(userOption), after all…
14:53
<devsnek>
does anyone else keep getting surprised that optional chaining doesn't work with assignment
14:58
<devsnek>
jschoi: i think they mean this https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAWwIYAcA8AVANIgVQD4AKYALkRIDdLsBKRAXiMPspNToG0BdRloT6IA3gChEkxACcAplBDSkNVABsQsgM49+zVtTUbNAOjToy9ANxiAvmLEQEmqIlTTpqAJ7NE3EQCNKAEYbXmszEk4BVlRjf3pOdy8rIA
14:58
<devsnek>
i'd say that's just a dumb limitation of TS though, and you can manually annotate it, so i don't think it matters
15:04
<jschoi>
Huh, I see. So the problem is that TypeScript cannot infer the type of even map(user => user.name)(userOption)…but, apparently, somehow it can infer the types in pipe(userOption, map(user => user.name))? 🤔
15:05
<devsnek>
yeah for some reason it doesn't unify the types in the former case
15:05
<devsnek>
personally i'd say its probably just better for microsoft to fix that
15:08
<jschoi>
I wonder if the TypeScript team has tried adding that inference but there’s a fundamental reason why they can’t, hmm. Anyways, thanks for help!
15:09
<devsnek>
its weird cuz its not really even an inference, it's just unifying unknown and {b: number} :/
15:16
<jschoi>
jschoi: i think they mean this https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAWwIYAcA8AVANIgVQD4AKYALkRIDdLsBKRAXiMPspNToG0BdRloT6IA3gChEkxACcAplBDSkNVABsQsgM49+zVtTUbNAOjToy9ANxiAvmLEQEmqIlTTpqAJ7NE3EQCNKAEYbXmszEk4BVlRjf3pOdy8rIA
I’ll use your example in my reply on that issue, if that’s okay.
15:16
<devsnek>
sure
15:19
<jschoi>
Hm, maybe it’s a fundamental limitation of how TypeScript’s “type inference works left to right”.
15:21
<jschoi>
Perhaps in map(user => user.name)(userOption) it can’t unify the types of user and userOption because…I don’t know, maybe it’s somehow unidirectional, it expects a type right away in that arrow function, and it eagerly throws an error right there before moving onto (userOption)? I wonder how solvable this would be for the TypeScript team, but having to use pipe functions seems like a pretty brittle way to work around it.
15:41
<jschoi>
Hmmm. https://github.com/microsoft/TypeScript/issues/15680 https://github.com/microsoft/TypeScript/issues/25826 https://github.com/microsoft/TypeScript/issues/30134
17:09
<TabAtkins>
Okay yeah sounds like it's just "we don't actually unify types, just do some inference tricks that fail in a lot of cases", but I'm still confused why pipe(val, map(user=>user.name)) infers properly.
17:19
<devsnek>
tsc continues to befuddle me
17:20
<devsnek>
TabAtkins: it seems to just be the order in which the graph is visited, one of those issues has an example of changing the order of arguments breaking inference
17:23
<TabAtkins>
Yeah, seems like there's some special-casing thrown around to address some cases. If this becomes a big issue, I suspect TypeScript can special-case "trailing (^) in a pipe body" and make it work like we'd expect, even without full inference.
17:33
<devsnek>
apparently the swc person is writing a new typescript type checker
17:33
<devsnek>
maybe it can handle this properly
18:56
<bakkot>
we should make let { #x: a } = foo work, to mean let a = foo.#x: y/n?
18:57
<bakkot>
I have seeded the emoji reacts so you can more easily just click on the appropriate one to express your opinion
18:57
<TabAtkins>
Tho let {#x} = foo; would still not work, right?
18:59
<bakkot>
yup
18:59
<bakkot>
or at least I am not proposing to allow it, and I think it should not work
19:47
<Domenic>
My personal opinion is that renaming while destructuring is generally distasteful, so I am not voting. (I.e. I think let x = y.z is clearer than let { z: x } = y.)
19:53
<devsnek>
i vote for whatever increases the number of productions in the spec