17:15
<ljharb>
mathiasbynens: is there a reason that we wouldn't want something like https://github.com/orling/grapheme-splitter in the language?
17:53
<mathiasbynens>
ljharb: that’s Intl.Segmenter
17:59
<ljharb>
mathiasbynens: right, but i meant directly on strings
18:46
<jridgewell>
What are you asking for?
18:46
<gibson042>
what would you expect from implementations that don't include ECMA-402?
18:46
<jridgewell>
What would "directly on strings" mean?
18:47
<devsnek>
like String.prototype.graphemes or something?
18:47
<ljharb>
sure
18:48
<jridgewell>
I think that'd run a huge risk of breaking changes?
18:49
<jridgewell>
Every time we update Unicode, you're `"foo".graphemes` could return something different.
18:49
<jridgewell>
your**
18:50
<ljharb>
breaking changes as a result of updating unicode already happen and are already Fine™
18:50
<ljharb>
the same could occur with code points, and *has* occurred with whitespace
18:51
<jridgewell>
As a syntax change, early errors are easy to fix.
18:51
<jridgewell>
This is a change in runtime behavior.
18:51
<jridgewell>
Much more difficult to track donw.
18:53
<ljharb>
right, those already have happened and will continue to happen when unicode updates
18:53
<jridgewell>
How?
18:53
<ljharb>
`.trim()` changed, for example, wrt the mongolian vowel separator in ES2017 iirc?
18:53
<ljharb>
that character got classified as whitespace, and then unclassified as it (or maybe the reverse, i don't recall)
18:53
<ljharb>
ie the meaning of `\s` in regexes changed
18:54
<ljharb>
so i don't think that "unicode changes" is an argument against adding any string-related features
18:54
<devsnek>
what is the benefit of having the api on string.prototype
18:54
<devsnek>
we already have the segmenter api
18:54
<ljharb>
devsnek: Intl isn't required, it's optional
18:54
<ljharb>
devsnek: so it's not guaranteed to be available
18:54
<devsnek>
the prototype method would have to be just as optional
18:55
<devsnek>
like toLocaleString
18:55
<rkirsling>
^
18:55
<ljharb>
why would it have to be?
18:55
<ljharb>
code points depend on unicode, and Symbol.iterator is required
18:55
<ljharb>
(toLocaleString is also required, it's just that its behavior is impl-dependent)
18:55
<ljharb>
(and 402 overrides it when present)
18:56
<rkirsling>
yeah but I don't believe XS uses ICU, say
18:57
<mathiasbynens>
segmentation is locale-dependent, at least for words and sentences, so Intl.* makes sense
18:58
<mathiasbynens>
having one type of segmentation on String.prototype.* and two others on Intl.* would be weird
18:59
<ljharb>
right, i don't think a generic segmenter belongs on strings
18:59
<devsnek>
ljharb: wait do you want
18:59
<ljharb>
but like you can iterate on chars, and on code points, i want to be able to iterate on graphemes
18:59
<devsnek>
Intl.Segmenter on String.prototype or
18:59
<devsnek>
the code point iterator
19:00
<ljharb>
ie, `'a🏳️‍🌈c'` is 8 chars, 6 code points, but 3 graphemes
19:00
<ljharb>
so i want an iterator that gives me 3 things and not 6 or 8
19:01
<ljharb>
i realize this is a subset of what Intl.Segmenter does, but it feels to me like the subset would make sense directly on String.prototype, mandated (unless that, too, is locale-dependent?)
19:01
<devsnek>
splitting by graphemes needs locale data right?
19:01
<devsnek>
like you'd bring in the icu lib
19:02
<ljharb>
maybe? what locale data does it need
19:02
<devsnek>
at which point you'd expose Intl.Segmenter anyway
19:02
<ljharb>
does the data needed for splitting on graphemes equal the data needed for all of Intl?
19:02
<ljharb>
i'd assume it's a small subset
19:03
<devsnek>
i mean that's true for each individual item we ship in Intl
19:03
<devsnek>
though some are larger than others
19:04
<ljharb>
mathiasbynens: can you explain how splitting grapheme clusters is locale-dependent?
19:07
<devsnek>
CLDR contains data for grapheme clustering
19:08
<ljharb>
right but i mean like, there's graphemes that aren't clustered consistently across locales?
19:09
<jridgewell>
https://unicode.org/reports/tr29/#Conformance
19:10
<jridgewell>
> For example, reliable detection of word boundaries in languages such as Thai, Lao, Chinese, or Japanese requires the use of dictionary lookup, analogous to English hyphenation.
19:10
<jridgewell>
It's not as simple as "does this char join with the previous char"
19:10
<jridgewell>
There's not a property on the Unicode char that we could look at.
19:11
<rkirsling>
word boundaries are tricky for sure, but ljharb is just concerned with graphemes
19:11
<ljharb>
right, i don't care about words
19:13
<jridgewell>
> These algorithms can be adapted to produce tailored grapheme clusters for specific locales or other customizations, such as the contractions used in collation tailoring tables.
19:13
<devsnek>
> The following is a general specification for grapheme cluster boundaries—language-specific rules in [CLDR] should be used where available.
19:16
<rkirsling>
stuff like 👨‍👩‍👧‍👦 is also an issue, dependent on env but not locale
19:20
<rkirsling>
https://mathiasbynens.be/notes/javascript-unicode#other-grapheme-clusters
19:24
<ljharb>
"For a completely accurate solution that works for all Unicode scripts, implement this algorithm in JavaScript, and then count each grapheme cluster as a single symbol"
19:24
<ljharb>
sounds like it's doable
19:25
<rkirsling>
oh here we go
19:25
<rkirsling>
jridgewell's last quote above precedes this table
19:25
<rkirsling>
https://unicode.org/reports/tr29/#Table_Sample_Grapheme_Clusters
19:25
<rkirsling>
the last chunk of the table is locale-specific
19:26
<ljharb>
so we could have it on string, and let 402 fill it in for the last chunk
19:27
<devsnek>
or you could just use Intl.Segmenter
19:31
<jridgewell>
https://www.irccloud.com/pastebin/TfliWeVm/simple-graphemes.js
19:32
<gibson042>
default rules for identifying grapheme cluster boundaries: http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
19:32
<shu>
PSA: please add incubator call items at https://github.com/tc39/incubator-agendas/blob/master/2020/04-14.md
19:32
<shu>
empty so far, i plan to add realms by EOD, but would like to give other folks a chance to add their items first
19:32
<gibson042>
they depend upon character property data, but are not locale-specific
19:32
<devsnek>
jridgewell: that doesn't yield anything
19:33
<jridgewell>
Did for me
19:33
<rkirsling>
I mean, it is a fact that https://github.com/orling/grapheme-splitter/blob/master/index.js is intending to implement the standard, and is <1750 lines with no deps
19:33
<rkirsling>
and has no locale arg, I mean
19:33
<ljharb>
jridgewell: [...graphemes('🏳️‍🌈💩')]` gives me just a single white flag
19:33
<jridgewell>
Oh, because I had a `Mark` char in mine.
19:34
<mmarchini>
has there been any proposals so far to investigate improving ergonomics of `const` and `try/catch`? `let res; try { res = await fetch(url); } catch (e) { /* ... */ } /* res can be overriden */`
19:35
<devsnek>
mmarchini: ergonomics of statements in general
19:35
<ljharb>
mmarchini: do expressions
19:35
<devsnek>
yep
19:35
<ljharb>
mmarchini: https://github.com/tc39/proposal-do-expressions
19:35
<jridgewell>
http://unicode.org/reports/tr29/#Table_Combining_Char_Sequences_and_Grapheme_Clusters
19:35
<jridgewell>
Wanna code that table into a regex?
19:36
<ljharb>
jridgewell: did you just ask me to write a distributed map reduce function in erlang
19:36
<ljharb>
:-p
19:36
<mmarchini>
do expressions implicitly returns the last expression, right?
19:36
<jridgewell>
No, we have the ability to encode it with properties.
19:36
<jridgewell>
I just don't wanna do it.
19:37
<devsnek>
mmarchini: not exactly
19:37
<devsnek>
but more or less yes
19:37
<ljharb>
jridgewell: was referencing https://lh3.googleusercontent.com/proxy/Qx2opykPRGCvHcvcqdfCxygjKoFmE4ZXMKuUB0fWV2KB2NMnAoS_AGBlt4M0k99imlqraTw2k55_y8oSNkD3iSgcFl2Bu9PYnsh9YNjfrpU8OrXZWcgi1emZvQ
19:37
<devsnek>
mmarchini: they work the same as what eval() returns
19:37
<ljharb>
shu: what's the process for adding things to "chartered proposals"?
19:37
<rkirsling>
there's also the explicit resource mgmt proposal
19:37
<shu>
ljharb: you want to talk about another proposal?
19:38
<mmarchini>
so the above would look like `const res = do { let res; try { await res(url) } catch (e) { /* ... */ }; res}`
19:38
<mmarchini>
oh, I don't think I'm familiar with how eval returns
19:38
<devsnek>
mmarchini: you can get rid of the res variable
19:39
<shu>
ljharb: the current process is to wait until the next plenary. people said they didn't want to feel pressured to check on an agenda every 2 weeks, so the proposed process was folks are free to call out proposals they think should be discussed in the incubator meetings in between two plenaries
19:39
<devsnek>
`do { try { x } catch { y } }`
19:39
<ljharb>
shu: i don't have anything in mind, just was curious
19:39
<mmarchini>
`const res = do { try { res(url) } catch (e) { console.error(e); undefined }}`?
19:39
<rkirsling>
shu: oh I missed that point, that's good to know
19:39
<shu>
ljharb: and so the stakeholders would be able to get a heads up and agree to participating in the call until the next plenary
19:39
<ljharb>
mmarchini: console.error already returns undefined
19:39
<ljharb>
shu: gotcha
19:39
<mmarchini>
right
19:39
<devsnek>
at that point
19:40
<mmarchini>
`const res = do { try { res(url) } catch (e) { undefined }}`
19:40
<mmarchini>
oops
19:40
<mmarchini>
`const res = do { try { res(url) } catch (e) { console.error(e) }}`
19:40
<mmarchini>
hum
19:40
<mmarchini>
interesting
19:40
<devsnek>
i'd do `await fetch().catch((e) => console.error(e))`
19:40
<mmarchini>
a little verbose, bot not bad
19:40
<mmarchini>
but*
19:40
<mmarchini>
gotcha
19:41
<ljharb>
indeed, devsnek's is better :-)
19:41
<ljharb>
do expressions are super useful but a lot of the examples could be easily reworked to be better, and not need do expressions in the first place
19:42
<rkirsling>
there's also https://github.com/tc39/proposal-explicit-resource-management for `try (const ...) {}` though
19:42
<rkirsling>
oh wait my bad
19:42
<ljharb>
that doesn't make the variable available outside the try
19:42
<rkirsling>
yeah
19:42
<rkirsling>
available outside with const, was the goal
19:42
<rkirsling>
sorry
19:42
<devsnek>
i really want do expressions :(
19:42
<ljharb>
same
19:42
<rkirsling>
ditto
19:43
<devsnek>
as long as they allow return and break and stuff that is
19:43
<devsnek>
without those they're useless to me
19:44
<ljharb>
oh, i want them to not have those things
19:44
<devsnek>
it doesn't even make sense for them to not have those
19:44
<ljharb>
it doesn't make sense to me to have an expression able to affect control flow (beyond throwing)
19:44
<devsnek>
it's a block
19:44
<devsnek>
that you can get a value out of
19:45
<ljharb>
right, the latter imo trumps the former
19:45
<ljharb>
things you can get a value out of, can't affect control flow, modulo exceptions
19:45
<devsnek>
i don't understand how "get a value out of" has anything to do with scope
19:45
<mmarchini>
I find do expressions very confusing without explicitly return
19:45
<mmarchini>
explicit*
19:46
<mmarchini>
"it behaves like eval" will not be a valid explanation for most JS developers
19:46
<ljharb>
i think it's a valuable thing to know that `return`, for example, can't occur in expression position
19:46
<mmarchini>
s/valid/didactic/
19:46
<devsnek>
i'm just imagining how useless block expressions would be in rust if you couldn't break/return out of them
19:46
<ljharb>
devsnek: what are your use cases for do expressions that need these?
19:46
<devsnek>
that i want to return from a function or break a loop
19:46
<ljharb>
right but what would the code be
19:46
<devsnek>
it doesn't matter
19:47
<mmarchini>
it doesn't have to be `return`, but making explicit in the expression what value is getting out would be important IMO
19:47
<ljharb>
it definitely matters - i can't conceive of when you'd need to return, or break, but also extract a value out of the code
19:47
<ljharb>
mmarchini: it couldn't be `return` due to confusion; but syntactically marking the value to get out would probably be tricky
19:47
<devsnek>
i wish github had better code search
19:47
<devsnek>
you should go look at rust code that uses block expressions
19:48
<ljharb>
different languages have different common use cases; i'd want an example in JS where you'd use this
19:48
<devsnek>
i have some logic
19:48
<devsnek>
inside a block
19:48
<devsnek>
that necessitates returning
19:48
<ljharb>
then why do you need to capture the value of the block
19:48
<mmarchini>
ljharb I think I get where you coming from: those are expressions and not blocks
19:48
<devsnek>
because its conditional or smth idk
19:49
<ljharb>
right, it's "do expressions" not "do blocks"
19:49
<ljharb>
devsnek: lol well if you don't know then how is it a use case
19:49
<mmarchini>
so maybe the bracked syntax is what's confusing me (and I expect it would confuse other folks as well)
19:49
<devsnek>
ljharb: i have specific code i would like to write
19:49
<devsnek>
but i don't think that's important
19:49
<mmarchini>
and in this case try/catch and if/else shouldn't be allowed, right? since we're avoiding any kind of control flow
19:49
<devsnek>
what
19:50
<devsnek>
y'all seem to really be missing the point
19:50
<mmarchini>
(not saying I'm agreeing with it)
19:50
<ljharb>
devsnek: without code, how can we avoid missing it
19:50
<ljharb>
mmarchini: nah, exceptions are fine
19:50
<rkirsling>
the real goal of do exprs is the wish that we could have "everything is an expression" in JS
19:50
<ljharb>
mmarchini: expressions can still throw
19:50
<ljharb>
rkirsling: but, explicitly instead of implicitly
19:50
<ljharb>
rkirsling: i actively don't want implicit expressions everywhere, i *like* the statement/expression dichotomy, and wish functions aren't both
19:51
<devsnek>
ljharb: why do you not believe i would want to use return inside a block
19:51
<devsnek>
i
19:51
<devsnek>
i'm sure you've used return inside blocks before
19:51
<ljharb>
devsnek: i use return inside blocks all the time, that's not the issue
19:51
<ljharb>
devsnek: i'm not understanding why you'd do that *and* want to capture the value of the block
19:51
<rkirsling>
ah okay. I would just as well not have statements in a language myself, but regardless, implicit would be quite a language revamp
19:51
<devsnek>
because both are useful
19:51
<devsnek>
orthagonally
19:51
<rkirsling>
therefore `do { ... }` is explicit
19:51
<ljharb>
devsnek: i'm not disputing it, i'm asking for a single non-contrived concrete example of it being useful
19:52
<devsnek>
ljharb: expanding my macros in engine262
19:52
<ljharb>
can you link me to an example?
19:52
<jridgewell>
ljharb: because capturing the value of the block is the entire point
19:52
<devsnek>
https://github.com/engine262/engine262/blob/master/scripts/transform.js
19:53
<rkirsling>
but I would think that that means that `do` just means putting a _scope_ around "everything is an expression" and not restricting what (would-be) statements are allowed in there
19:53
<devsnek>
like `do if () {}`?
19:53
<jridgewell>
https://www.irccloud.com/pastebin/2hSLTTCi/do-expression-return.js
19:54
<jridgewell>
You can't always devolve an the remaining part of a block into an else condition.
19:54
<rkirsling>
devsnek: tbf `do if` is just somebody complaining about ternaries
19:54
<jridgewell>
rkirsling: ternaries don't allow variable delcarations
19:55
<devsnek>
jridgewell: everything after an if+return is implicitly the else bock
19:55
<bradleymeck>
do with return gets really weird/new
19:55
<devsnek>
block
19:55
<jridgewell>
Blocks are necessary to cleanly express a lot of code
19:55
<jridgewell>
devsnek: You can't always devolve an the remaining part of a block into an else condition.
19:55
<bradleymeck>
i think its a good idea, but doubt we should use the `do` keyword due to how gross the `do...while` interactiom is
19:55
<devsnek>
why can't i refactor any `let x; <some statement or block>` to `let x = do { <some statement or block> }`
19:56
<jridgewell>
My code example is contrived, and is just meant to demonstrate early return
19:56
<ljharb>
jridgewell: ok so can you give me an example of when you *can't* devolve the rest of the block into an else?
19:56
<devsnek>
jridgewell: you want to early return to the end of the do block?
19:56
<ljharb>
jridgewell: i'm not saying "there are none", i'm saying "please give me one because nobody seems to be capable of doing that so far"
19:56
<devsnek>
i've never not been able to devolve into an if+else in rust
19:56
<jridgewell>
At the beginning
19:56
<rkirsling>
jridgewell: to be clear I meant `do if` as opposed to `do { if {} }`
19:56
<devsnek>
jridgewell: i've never encountered something that can't be
19:57
<jridgewell>
const x = do {
19:57
<devsnek>
?
19:58
<jridgewell>
This can't be cleanly develoved into an if-else. https://www.irccloud.com/pastebin/bmg0madZ/do-expressions.js
19:58
<jridgewell>
Again, contrived.
19:58
<jridgewell>
But every set if conditions can't be cleanly devloved into an if-else.
19:58
<devsnek>
it can be
19:58
<jridgewell>
But not**
19:58
<devsnek>
it would take a few minutes of thinking
19:59
<jridgewell>
**cleanly**
19:59
<devsnek>
and i'd argue that's spaghetti with or without do expressions
19:59
<jridgewell>
I don't want to repeat `doSomething()`
19:59
<jridgewell>
It's a fallthrough, which is very valuable.
20:00
<ljharb>
jridgewell: sure it can `if (first) { if (second) { something; } else { doSomething(); } } else { doSomethingMore(); value; }`
20:00
<ljharb>
and then you return that entire thing wrapped in `do { }`
20:01
<jridgewell>
Nit picking my example isn't really the point.
20:01
<ljharb>
i'm still seeing some very smart people struggling to come up with a single non-contrived concrete example of where it'd be useful to have return/break/continue inside a do expression, which doesn't bode well for the persuasiveness of the argument
20:01
<bradleymeck>
i think assigning to a var might be part of the issue with this basis, putting them inside awkward expression positions feels more concrete: `foo({x: existing ?? do { try { /*expensive*/ } catch { /* better message here */ } })`
20:01
<jridgewell>
Do this with a for-loop, where you early return.
20:01
<devsnek>
jridgewell: i've literally only ever seen logic that contrived in my js lexer
20:02
<ljharb>
bradleymeck: that example is fine, there's no return/break/continue in it
20:02
<bradleymeck>
ljharb: i mean i can make a return based example in there
20:02
<devsnek>
y'all should really try using some languages with this behaviour
20:02
<bradleymeck>
such as things that fail silently
20:02
<ljharb>
bradleymeck: i'd love to see my first non-contrived one
20:02
<bradleymeck>
i don't think contrived is a valuable position
20:03
<bradleymeck>
we have a turing complete language, everything is contrived
20:03
<devsnek>
ljharb: it occurs to me you can have a no-return-in-do-expression eslint rule
20:04
<bradleymeck>
i'd lean on allowing usages rather than trying to pin the language down to only having 1 way to accomplish anything
20:04
<ljharb>
devsnek: sure, but why add burden for those that lint if there's not a compelling argument to allow it in the first place
20:04
<devsnek>
well we shouldn't have 20 ways to accomplish something, but you should be able to compose features into new ways of using them
20:05
<devsnek>
ljharb: i would use it
20:05
<devsnek>
i feel like 95% of my arguments turn into people saying my use cases aren't valid
20:05
<ljharb>
devsnek: and all i've been asking for is, to see some JS code where you'd use it :-/
20:05
<devsnek>
ljharb: i linked you to an example
20:05
<ljharb>
i'm not saying your use cases aren't valid, i'm saying "please give me > 0 use cases"
20:05
<bradleymeck>
`for (...) { results.push(do { try { ... } catch { continue } }) }`
20:05
<ljharb>
devsnek: in JS? or in rust
20:05
<devsnek>
that transform code isn't even feature complete
20:05
<devsnek>
i linked you some js
20:06
<ljharb>
oh, let me take a look
20:06
<devsnek>
bradleymeck: more generally, wherever you'd normally want to express control flow, you might want to do so if that logic happens to occur inside a do expression
20:06
<ljharb>
devsnek: any lines in particular?
20:07
<devsnek>
ljharb: the entire thing is a system to restructure random expressions into using control flow
20:07
<bradleymeck>
devsnek: i mean thats the complaint with arr.forEach in general vs loops
20:07
<devsnek>
and like i said its not complete, there are certain ways you can't use macros in engine262 because i haven't figured out how to transform them correctly
20:07
<bradleymeck>
the only thing with do expressions is they can live in an expression position
20:09
<bradleymeck>
so, things that want to skip an effect while being in an expression position such as the .push example above are prime examples
20:09
<devsnek>
the argument i did find interesting was that someone would be confused about return inside a do expression and whether it returned the block or the enclosing function
20:09
<devsnek>
but i think that's more of a general language education problem
20:09
<bradleymeck>
you could refactor things into a lot of statements, or you could keep the bailout logic in the literal 🤷
20:10
<bradleymeck>
for what it is worth, i think return/continue/break are scary, but have no clear reason to argue against them as you could refactor things to be done w/o do expressions anyway; that just makes it more verbose / may increase loss of locality
20:11
<bradleymeck>
labelled break/continue are super interesting here
20:11
<devsnek>
labels are illegal
20:11
<bradleymeck>
in the proposal? we have power to alter such things
20:11
<devsnek>
no i meant in general, it was a joke
20:12
<bradleymeck>
i use labels!
20:12
<devsnek>
i've only used labels once
20:12
<devsnek>
for lexing whitespace in js
20:12
<devsnek>
nested loop sadness
20:12
<bradleymeck>
i use em in bad places
20:12
<bradleymeck>
like_here: debugger;
20:12
<devsnek>
why do you label a debugger statement
20:13
<bradleymeck>
gives me my debugger operands proposal effectively /cackling
20:13
<devsnek>
wait i don't think that syntax is even valid
20:13
<devsnek>
LabelledStatement and DebuggerStatement are both productions of Statement directly
20:13
<bradleymeck>
browsers think it is
20:14
<devsnek>
wait a second
20:14
<devsnek>
LabelledItem is any statement
20:14
<devsnek>
this changes everything
20:14
<bradleymeck>
yes, they can even nest
20:14
<bradleymeck>
if i remember
20:15
<bradleymeck>
what does it change?
20:16
<bradleymeck>
devsnek: are you just gonna add a ton of labels?
20:16
<devsnek>
lol it doesn't actually change much
20:16
<devsnek>
i just never realized you could label things that aren't loops
20:16
<bradleymeck>
i thought you were about to do something weird like
20:17
<bradleymeck>
return_if_abrupt: foo();
20:17
<ljharb>
you can break to a label without a loop as well, i think
20:17
<bradleymeck>
yea
20:18
<devsnek>
aw i was hoping this would work `x: { console.log('hi!'); while (true) { continue x; } }`
20:19
<bradleymeck>
nah, just break
20:19
<devsnek>
also TIL break is not constrained to loops
20:19
<devsnek>
what a wild world
20:20
<bradleymeck>
why would it be?
20:20
<devsnek>
what are you breaking if you aren't in a loop
20:21
<ljharb>
the quality of your code
20:21
<devsnek>
lol
20:21
<devsnek>
`x: { console.log('hi!'); break x; console.log('bye') }`
20:21
<devsnek>
so this doesn't log bye
20:22
<devsnek>
you could use that for early return in do expressions
20:28
<bradleymeck>
that isn't the same, the completion value would carry over rather than stop outer scope
20:30
<devsnek>
jridgewell's example https://gc.gy/53996426.png
20:31
<ljharb>
devsnek: fwiw i don't mind anything that breaks out of the do expression; but that you could put the label anywhere seems like it'd be bad
20:31
<devsnek>
wdym
20:31
<ljharb>
devsnek: so like, i'd be ok with a do-expression-level unlabelled break
20:31
<devsnek>
unlabelled break has to go to the enclosing loop
20:31
<ljharb>
not if it's inside a do expression
20:32
<ljharb>
(you can make a consistency argument that it must, sure, but i'm saying it could have different semantics there)
20:32
<devsnek>
why do things have to randomly be different inside the block of a do expression
20:33
<ljharb>
things are already that way, because of the completion value
20:33
<devsnek>
it's not a problem to use if/else in rust
20:33
<ljharb>
no other blocks are expresisons
20:34
<rkirsling>
wait, was the statement about `break` just in the context of do exprs?
20:34
<ljharb>
rkirsling: which statement
20:34
<rkirsling>
the idea that you could use it as goto in general
20:34
<ljharb>
no, you can already do that
20:34
<rkirsling>
how?
20:34
<ljharb>
outside of a loop, you can't use an unlabelled break; but you can use a labelled break anywhere
20:35
<devsnek>
you can't use it as goto
20:35
<rkirsling>
that's deeply horrifying but also I can't get that to happen in eshost whatsoever
20:35
<devsnek>
https://gc.gy/53996740.png
20:35
<ljharb>
oh hm, maybe it's only out of blocks
20:36
<devsnek>
you can't jump
20:36
<rkirsling>
ahh if it's just "break out of block" I'm less horrified
20:36
<ljharb>
`(function () { x: console.log('a'); break x; }())` says "undefined label x"
20:36
<ljharb>
ok yeah same
20:36
<rkirsling>
phew
20:37
<devsnek>
anyway
20:37
<devsnek>
people who are concerned about early exit from do expressions
20:37
<devsnek>
should try out languages which have blocks as expressions
20:37
<devsnek>
because its basically not a problem
20:37
<devsnek>
like every once in a while you have to refit something to be if/else but it's very trivial
20:38
<gibson042>
ECMAScript allows expressions in places like variable initializers
20:39
<devsnek>
it allows them in lots of places
20:39
<devsnek>
almost anywhere in fact
20:51
<gibson042>
more specifically, ECMAScript allows expressions in places where it _doesn't_ allow control statements
20:52
<devsnek>
it allows them in places where it doesn't allow statements
20:52
<devsnek>
control or otherwise
20:52
<gibson042>
a pathological example from an earlier meeting was something like `function foo(a = do { return }){}`
20:52
<ljharb>
^ that is something that imo shouldn't be possible
20:53
<devsnek>
🤷🏻 https://gc.gy/53997804.png
20:53
<devsnek>
seems well defined enough
20:53
<devsnek>
i'd expect a no-do-in-arg-init eslint rule regardless of whether they can contain control statements
20:54
<ljharb>
perhaps, but i wouldn't enable it
20:54
<rkirsling>
why not
20:54
<devsnek>
why shouldn't it be possible
20:55
<devsnek>
is what i'm curious about
20:55
<ljharb>
rkirsling: i wouldn't enable it because i don't think there's a problem with using a do expression as a default argument - in place of the places that might currently invoke a function instead
20:55
<devsnek>
well actually i know why it shouldn't be possible
20:55
<ljharb>
devsnek: in general, i lean towards all things should be prohibited unless its good usage outweighs its bad usage
20:56
<gibson042>
now do `function foo(a = do { continue }){}`
20:56
<devsnek>
it shouldn't be possible because arg init shouldn't be +Return
20:56
<bradleymeck>
i already have some "do" via iife in default arge for throwing
20:56
<devsnek>
gibson042: arg init can't contain an outer loop
20:56
<devsnek>
it's at the function boundary
20:56
<devsnek>
that's always an unsyntactic continue
20:57
<devsnek>
gibson042: the key here is that function arg init shouldn't be +Return, regardless of whether do expressions exist or not
20:57
<gibson042>
agreed
21:01
<Bakkot>
breaking non-loops is useful in almost exactly the set of cases when an early return is useful, it's just that usually you would refactor that code to use a function with an early return rather than keeping it inline. but that's not always something you want to do.
21:02
<devsnek>
yeah i pointed that out above with jridgewell's example
21:04
<Bakkot>
most of the places i've ended up emitting a non-loop with a label are in generated code
21:04
<Bakkot>
ljharb: re: grapheme clusters being locale-dependent, the example which always occurs to me is, there are some flags which correspond to entities whose status as "a state" (and therefore which qualify for a flag) is a matter not everyone agrees upon
21:04
<devsnek>
i've never even seen that in generated code
21:05
<devsnek>
would love to see some examples
21:05
<Bakkot>
which means flag emoji +ZWJ+their country code may, or may not, be a single character
21:05
<Bakkot>
devsnek: code I'm generating tends to be proprietary, alas
21:05
<devsnek>
oh this is code *you're** generating
21:06
<Bakkot>
well, it is code which tools I wrote are generating, at any rate
21:06
<ljharb>
Bakkot: oh meaning like taiwan, or palestine, to name the most controversial examples i can think of?
21:06
<devsnek>
i'm curious what higher-level control flow mapps to that output
21:06
<Bakkot>
ljharb I was extremely carefully in not naming examples :P
21:06
<Bakkot>
but yes
21:07
<ljharb>
Bakkot: that makes sense, but it still seems like something that could be addressed in a generic way (but Intl/locales could decide)
21:08
<gibson042>
Bakkot: I thought all the regional flags used regional indicators, which are always grapheme clusters per the default rules
21:08
<Bakkot>
devsnek the higher level control flow is usually functions which have early returns which I am inling
21:08
<devsnek>
i see
21:09
<Bakkot>
gibson042 the regional indicators may or may not be joined into a single unit depending on whether the code you're running recognizes that falg
21:09
<gibson042>
default rules include "Do not break within emoji modifier sequences or emoji zwj sequences" and "do not break between regional indicator (RI) symbols if there is an odd number of RI characters before the break point"
21:10
<Bakkot>
it's not breaking between the RI symbols, is whether you end up with just a colored flag (one grapheme), or a white flag + a regional indicator (two graphemes)
21:10
<devsnek>
now i kind of want to write a babel transform that does function inlining using labels
21:11
<gibson042>
that presentation detail is not relevant to grapheme cluster boundaries
21:11
<Bakkot>
I suspect it is relevant to the thing ljharb wants, though
21:16
<ljharb>
i think i'd be content with the default 262 impl being the default rules, and 402 imposing the locale-dependent ones on top of it
21:16
<ljharb>
(assuming it would do the "right" thing in most cases)
21:21
<rkirsling>
would be interested in hearing from engines that have no intention to implement 402 though
21:21
<gibson042>
if there were commitment to put it in ECMA-262, that would seem to be the best approach (specify default rules and let ECMA-402 override, similar to but better than how ECMA-262 specifies toLocale*)
21:22
<gibson042>
as of today, the default rules appear to require no information not already required of regex \p
21:22
<ljharb>
rkirsling: you can compile node to node include intl, and i don't think xs does
21:22
<ljharb>
*to not include
21:22
<ljharb>
rkirsling: node < 12 or 13 didn't include it by default, iirc
21:22
<rkirsling>
yeah XS doesn't, is a key example
21:22
<ljharb>
gibson042: thanks, that sounds good
21:23
<rkirsling>
my point is that engines that do implement 402 have ICU to use, even for a feature that might be 262-side
21:23
<rkirsling>
but XS would have to reimplement and maintain this logic themselves
21:24
<ljharb>
right
21:31
<gibson042>
but I don't know if it makes sense or not... grapheme cluster segmentation seems to occupy a gray area between code unit/code point segmentation (trivial, deterministic, time-invariant) and word/sentence segmentation (difficult, locale-dependent, and time-dependent)
21:33
<rkirsling>
yeah :-/
21:34
<rkirsling>
regex \p is a good point though, I wonder whether XS would opt out of that too
21:38
<rkirsling>
(I mean, they are currently opting out, but the question is would they ever change that)
21:39
<ljharb>
in the fullness of time, they'd have to implement anything that wasn't normative optional, no?
21:41
<rkirsling>
in theory, though I feel like that's kind of a new concept in 262 outside of Annex B?
21:41
<ljharb>
well, function toString returning source is normative optional via the host hook :-p
21:42
<rkirsling>
I guess I just mean that that phrase occurs in 402 but not in 262 at present
21:43
<ljharb>
oh, sure
21:44
<ljharb>
but i doubt they'd be able to get away with not implementing regex `\p` and still be 262-compliant
21:46
<rkirsling>
certainly, but they consciously ship with caveats: https://github.com/Moddable-OpenSource/moddable/blob/public/documentation/xs/XS%20Conformance.md#caveat
22:06
<Bakkot>
ljharb: backing up a step, I feel like grapheme segmentation is a thing I am unlikely to care about on platforms which lack Intl; is there a specific reason you care about having it on non-Intl platforms?
22:11
<ljharb>
i don't feel like i can rely on Intl in any of my code, because i want my code to be as portable as possible. i don't have a concrete use case for this right now, it's not a proposal :-) just asking out loud
22:20
<rkirsling>
it's a worthy discussion, but I'm not sure a portability argument holds water, if the places where it wouldn't work (in the long-term) are just memory-constrained places like microcontrollers
22:20
<rkirsling>
I don't think other engines are opting out so much as deprioritizing it?
22:21
<rkirsling>
(btw I'm removing JSC's ENABLE_INTL define as we speak 😉)
22:30
<shu>
removing it so it's always on?
22:31
<devsnek>
removing it so its always off
22:31
<shu>
sad trombone noises
22:31
<rkirsling>
on!
22:31
<shu>
happy trumpet noises
22:31
<rkirsling>
wherefore this disinformation
22:31
<devsnek>
lol
22:31
<devsnek>
now if we can just convince v8 to always ship intl
22:32
<rkirsling>
gonna assume the Intl object exists and then we can just runtime-guard new classes
22:32
<rkirsling>
(there was only one upstream platform flipping it off, is why this should be okay to simply do as maintenance)