09:02
<Jack Works>
CharacterClassEscape[UnicodeMode] :: 
[+UnicodeMode] p{ UnicodePropertyValueExpression }
[+UnicodeMode] P{ UnicodePropertyValueExpression } 

Is it missing a [+UnicodeSetsMode] version of those 2 production? otherwise I cannot find a way to parse /^\p{Basic_Emoji}+$/v

10:26
<jmdyck>
In the spec, +UnicodeSetsMode only occurs in conjunction with +UnicodeMode. (i.e., roughly, +USM implies +UM, or +USM is a subset of +UM), so any RHS guarded by [+UM] 'succeeds' for all cases of +USM.
10:26
<jmdyck>
I think.
11:08
<Jack Works>
oh, I checked all Pattern, all Pattern[+USM] is also marked as [+UM]
11:29
<jmdyck>
yup
17:25
<bakkot>

I want to make a proposal for a method for finding the item in an iterable which has the largest value according to some function, for example "find the person with the largest age" or whatever. This comes up a lot IME, enough to be worth having in the standard library even though it's like a four or five lines to do with a loop or .reduce.

There's two natural ways to do this: either take a function from input items to a number, or take a comparator. both work, first is often more convenient, second is strictly more general.

Thoughts? We could in principle support both. (Even in the same function, just by switching on callback.length === 1, but... not that option.)

17:28
<bakkot>
I suppose one way to solve the dilemma is to have a function which lifts a T -> number mapper to a (T, T) -> { -1, 0, 1 } comparator, and expect people to use that, as in people.maxByComparator(Compare.by(person -> person.age)).
17:28
<bakkot>
(java calls the latter operation Comparator.comparing)
17:35
<Michael Ficarra>
Isn't this the same API design question we had with uniqueBy? You can either give a mapper or a comparator, and we probably just want both.
17:36
<Michael Ficarra>
wouldn't this be less efficient?
17:36
<bakkot>
Pretty similar, yeah, although the "comparator" for uniqueBy is not a comparator in the sense of "a function which can be passed to .sort", whereas it is here
17:37
<bakkot>
same big-O, but requires computing 2x as many calls of the T -> number function, yes
17:39
<bakkot>
I actually am kind of coming around to the idea of switching on the .length of the callback
18:07
<Ashley Claymore>
A comparator for unique has to compare against all previous unique values. O(N^2)
A comparator for largest only has to compare against the current winner. O(N)
18:08
<Ashley Claymore>
This does sound useful. I currently reach for `.sort(c).at(-1)` when in a pinch 
18:10
<eemeli>

Effectively, this would be sugar for something like this, yes?

people.reduce((acc, person) => person.age > acc.age ? person : acc)
18:17
<eemeli>
Isn't that good enough for this use case?
18:23
<bakkot>
I mean, isn't a for loop good enough for this use case?
18:23
<Ashley Claymore>
Reduce has the "empty list" exception which is annoying IMO
18:23
<Ashley Claymore>
for a winner like method I'd rather an empty set returns undefined as the winner 
18:25
<bakkot>
reduce is basically the same kind of hammer as a for loop. Personally I like it when the language provides common, simple operations even when they're already achievable with the language's existing general purpose tools.
18:25
<bakkot>
ehhhhh no I was definitely planning on proposing this where it's an exception if you call it on an empty list
18:25
<Ashley Claymore>
https://es.discourse.group/t/array-prototype-winner/1015/
18:26
<bakkot>
("winner" is a terrible name)
18:27
<Ashley Claymore>
Only a weakly held opinion. I'd be curious what other languages do (the ones that can't return a fancy maybe type)
18:28
<Ashley Claymore>
Passing an initial value to reduce to avoid the throw is annoying because you can't easily pass `undefined` as that will get passed as an argument, so now need to handle that extra case on the comparator 
18:29
<eemeli>
You can avoid this by passing a sentinel value as the second argument, e.g. { age: -Infinity } in the example case.
18:29
<Ashley Claymore>
Sure, now do that with a complex type with more than one prop :)
18:31
<Ashley Claymore>
Returning undefined I can always `?? error()` to get back to the exception behavior. Going from exception to undefined is more work 
18:32
<eemeli>
people.reduce((acc, person) => person.age > acc?.age ?? -Infinity ? person : acc, null)
18:32
<bakkot>
python's max has an optional default argument to use in case of empty list, and throws if the list is empty and no default is provided
18:32
<bakkot>
which seems pretty reasonable
18:33
<bakkot>
other languages return fancy maybe types
18:33
<bakkot>
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#max-java.util.Comparator-
18:34
<bakkot>
https://docs.rs/itertools/latest/itertools/fn.max.html
18:34
<Ashley Claymore>
a default that is only used for empty sounds good, that isn't passed to the comparator 
18:35
<Michael Ficarra>
god this language could've been so much better if we had a built-in Maybe in the early days
18:35
<eemeli>
Or allowed any breaking changes ever.
18:35
<Ashley Claymore>
And monoid protocols
20:05
<JaseW>

So Rust has both max and max_by methods on iterators where the later takes a comparator function and the former only works with values that implement “Order”, so mainly numbers etc

In Rust’s case they return an Option type then None if the list is empty, so undefined in the js equivalent.

https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by

That being said, Option is a fancy return type, so doesn’t help here. But I do like the max and max_by names better.

20:09
<Ashley Claymore>
Maybe empty vs unary arrays are the true JS option type, as you can't `null.map`.
I tried that in a codebase once when I was in my wild youth phase 
20:23
<bakkot>
max and max_by are the right names but rust has them exactly backwards :(
20:24
<bakkot>
sort takes a comparator, sortBy would take a T -> number
20:24
<bakkot>
ditto max and maxBy
20:25
<bakkot>
I guess the T -> number one is called max_by_key in rust
20:26
<bakkot>
but yeah I think the natural naming is max taking an optional comparator and maxBy taking a mandatory T -> number
22:41
<TabAtkins>
This is it, yes. Both variants are needed, and this is the right naming/assignment.
22:46
<Michael Ficarra>
@bakkot throwing or returning a special value for empty iterators?
23:02
<bakkot>
Michael Ficarra throwing but with an optional second default argument to return in that case, like python does
23:03
<bakkot>
though I guess that's annoying in the specific case that you want to use the default comparator but provide a default
23:03
<bakkot>
oh well I guess
23:03
<Michael Ficarra>
yeah I think that's what I would do as well
23:03
<Michael Ficarra>
still not 100% convinced it's needed, but if we do have it, that's how I would do it
23:06
<Michael Ficarra>
I definitely want unique/uniqueBy more
23:07
<bakkot>
I forget: given that we have no array prototype methods, how would those work? on iterator.prototype but returning array?
23:08
<bakkot>
I guess they could return an iterator, ok
23:09
<bakkot>
just kind of weird to have an iterator that uses O(all previous items) memory
23:31
<Michael Ficarra>
yeah that was the feedback I got at the last presentation
23:31
<Michael Ficarra>
it's weird but I don't think it's surprising if you consider for even a second what it's doing
23:32
<Michael Ficarra>
and I don't think that's fatal to the proposal