2019-01-30 [10:06:02.0000] channel logging requested by bterlson: https://freenode.logbot.info/tc39 [10:06:25.0000] can we get the libuv slurper [10:06:33.0000] it hasn't gone down in like 5 years [10:11:29.0000] is it possible to create a FAQ ? [10:12:14.0000] for JS in general? we're working on some related things, I think, yes [10:12:20.0000] im sure almost every person has wondered about the topic i spoke about. it would be waste of your time [10:24:08.0000] can people use mics? [10:25:03.0000] Maybe I'll still put a mail in regarding the single expression functions. Can't hurt to have it floating around on a more slow platform. Though I can definitely understand if it wouldn't make the cut :) 2019-01-31 [19:59:18.0000] if ecma262 had multipage [19:59:41.0000] should it be implemented in ecmarkup or by processing the output [20:06:16.0000] Definitely as part of ecmarkup. That could change whenever. That said what would be the goal? [20:10:17.0000] Sirisian: size and performance [20:10:31.0000] my cpu stays pinned around 50% just having the spec open [20:10:37.0000] can't even open it on my phone [20:10:43.0000] lots of people have similar issues [20:13:12.0000] I've only started looking at ecmarkup and it's various utility programs. Is it using real web components? [20:15:12.0000] They look real. nvm. Was thinking maybe it could be a polyfill thing. My computer is too fast to notice things. [20:29:10.0000] devsnek, Did you try profiling it? I noticed that "Hit Test"s take a while on the page. https://bugs.chromium.org/p/chromium/issues/detail?id=428083 [20:29:42.0000] Sirisian: its roughly 800 pages long [20:29:45.0000] its just really big [20:29:47.0000] Sirisian: it used to be a "real" web component thing, but rendering the giant document was extremely slow [20:29:58.0000] like, minutes to load slow [20:30:20.0000] so now the elements are preprocessed away, but nothing is stopping osmeone from making a CE implementation AFAIK [20:30:25.0000] might be nice for small specs? [20:33:37.0000] It would be naive, but hiding the different sections might be enough. It looks like hit tests are ran for every scroll/mouse move. Also the spec runs 100% fine on my old HTC 10? [20:34:01.0000] There's absolutely no lag. [21:24:59.0000] Sirisian: are you using Firefox? I've noticed the spec render smuch quicker in FF than Chrome [21:29:12.0000] I use both, but on mobile I use Chrome. [21:29:43.0000] I just noticed in Chrome the spec is so large you can't debug it. Only profile, but firefox can debug it. [21:56:28.0000] its surprisingly easy to parse the spec into json [21:56:39.0000] my compliments to the good structure of the build output [22:30:23.0000] ftr it works super fast in safari, which is the only place i've ever looked at it :-p [23:53:06.0000] Scala also uses = to indicate function implementations, it's just that most of the time that implementation is a block statement [00:10:42.0000] So https://tc39.github.io/ecma262/#sec-object-type only talks about get/set access to properties; but then there's also prose to the extent of "If O has an own property P" [00:12:26.0000] Context: https://github.com/heycam/webidl/pull/601 [02:17:10.0000] Hello Everybody :) Thanks for the invite @bterlson (in twitter) [04:58:56.0000] annevk: it looks like explaining what an "own" property is, and what "has" means are being requested? [04:59:35.0000] so what it means to have an own property and what it means to have properties otherwise [05:02:38.0000] bradleymeck: yeah, it's a lil vague how such statements work in terms of primitives defined in ES [05:08:28.0000] bradleymeck: it's also not always clear to what extent a host environment is allowed to use those primitives [05:11:12.0000] i would be surprised if a host ever directly used the prose instead of some abstract op or using internal slot methods, as internal slot methods are generally what you want for object ops that are not being done using the Reference Type [05:11:39.0000] we can try and figure out some note we can add though about when it is expected to use things maybe [05:14:13.0000] Well, in the IDL case we basically want "If |O| has an own property with name |P|", which ES also uses itself and doesn't really offer an abstraction for [05:49:43.0000] annevk: does O.[[GetOwnProperty]] not satisfy that, or are you wanting one specifically with a "Has" true/false return [05:50:28.0000] https://tc39.github.io/ecma262/#sec-hasownproperty exists, so i'm a little confused [05:51:43.0000] bradleymeck: did you read the IDL PR comments? [05:53:08.0000] annevk: i did [05:53:48.0000] i don't have a solution, but i'm just explaining what the spec has/generally should be used [05:53:56.0000] idk the visibility algorithm in depth though [05:57:13.0000] So we could use OrdinaryGetOwnProperty (need to bypass proxies iirc), but then we duplicate a whole lot of language that isn't really needed [05:57:35.0000] So then the question is if we can use the language around Objects [05:57:56.0000] And then a side question is how much that language is formalized enough, as the section on Object itself only talks about get/set, not has [06:00:02.0000] i think we could expose something about prose in ECMA262 explaining "has" as it is not going to change, but I would probably want to figure out what is safe for a host to use with it since it gets around the meta object protocol intentionally [06:01:06.0000] i'm just not well informed enough on what this is trying to do [06:01:23.0000] the visibility explainer kind of explains the intent, but not all the details [06:04:54.0000] bradleymeck: afaik MOP are constraints on objects; when you define a host object, you need lower-level hooks, such as OrdinaryGetOwnProperty and in this case "has an own property" [06:06:33.0000] mmmm but this is changing how one of the methods on an object works from outside, maybe i'm confused [06:13:35.0000] bradleymeck: it's basically defining a new proxy object [06:13:57.0000] sorry, exotic object [06:15:42.0000] yea, but this seems new to me and i'm trying to process. [06:16:09.0000] the exotic object is fine, the visibility algorithm is always within a MOP operation so it is probably fine to use [06:17:03.0000] i think the prose we need to add is just about going through MOP operations *unless* you are creating an exotic object and are using things like "has" within a MOP operation implementation [06:17:18.0000] that seems ok? will talk to ppl today at meeting in case they miss this [06:17:51.0000] Yeah, and does "has" need to be grounded better somehow? [06:17:55.0000] using "has" outside of a MOP operation seems like something that would not be expected/should not be done [06:18:09.0000] Sure [06:18:15.0000] annevk: the meaning of "has" won't change but we can add a couple sentences being clearer [06:18:37.0000] I don't think anyone is asking for it to change, I'm mostly asking for it to be defined [06:18:54.0000] annevk: as an abstract op instead of a prose? [06:19:00.0000] No preference [06:19:19.0000] Although it does seem somewhat weird to me that not all of an object's layout is done using slots and abstract operations [06:19:32.0000] ok, i'll figure this out [06:19:45.0000] ta [06:20:14.0000] annevk: idk, slots being used would still devolve to a list of entries/map of properties [06:20:45.0000] this just isolates the spec level stuff from host/user level [06:21:08.0000] (though hosts can use slots) [06:23:59.0000] bradleymeck: fair, though it would be somewhat clearer that there's a container for this stuff [12:55:22.0000] michaelficarra: having not watched the presentation yet, what is the difference between your collect() modifications in https://github.com/tc39-transfer/proposal-iterator-helpers/issues/17 and reduce()? [13:01:42.0000] also interested ^ [13:12:50.0000] Domenic: you can build the collect with reduce, but you can do a lot of things with reduce [13:13:07.0000] It just sounds like the same thing, an initial value and an accumulator. [13:13:11.0000] collect is reduce special-cased to accept just the combination and the empty value [13:13:25.0000] reduce doesn't take an accumulator though [13:13:39.0000] What is the difference between the reducer and an accumulator? [13:13:41.0000] I can write collect in terms of reduce for you, hold on [13:13:58.0000] The only signature I can imagine for accumulator is (soFar, thisValue) => combinedValue, which is the reducer (modulo thisArg) [13:14:47.0000] `reduce((k, l) => [...l, k], [])` [13:15:01.0000] is collect [13:16:25.0000] Right, I think I'm with Domenic that the proposed mod to `collect()` are literally just `reduce()`. [13:17:46.0000] (Having a simple way to reduce into an Array is a good thing; I'm in favor of trivial `.collect()`.) [13:18:08.0000] agreed [13:20:21.0000] okay, the difference is a bit subtle [13:21:18.0000] reduce takes a "container" and an "entry" and combines them in some way, but the accumulator takes two "container"s and combines them [13:21:38.0000] the difference is that reduce would require you to provide a "pure"/"of" function as well [13:21:48.0000] consider me confused [13:22:05.0000] i guess i'll need to watch the presentation [13:24:07.0000] reduce :: (a -> b -> a) -> a -> f b; collect :: (f a -> f a -> f a) -> f a -> g a [13:24:10.0000] if that helps at all [13:24:41.0000] nope :D [13:26:38.0000] What would the second container be here? [13:27:01.0000] Given `Iterator([1,2,3]).collect((a,b)=>console.log(a,b)), what'll we log? [13:27:32.0000] what is your "empty" value? [13:27:40.0000] Assume it's `[]` [13:28:10.0000] then `[], [1]`, `[1], [2]` and `[1,2], [3]` [13:28:28.0000] assuming you also actually returned the concatenation [13:28:30.0000] ??? You're producing a *brand new* container to singly-wrap each of the items in the starting container? [13:28:48.0000] yes, because that's sometimes the only way you can do things [13:29:17.0000] Hmmmmm. Ok, I get that, sometimes the values in a monad can't be extracted directly. [13:29:34.0000] that's right [13:29:44.0000] unless they're also comonads :-) [13:29:52.0000] It doesn't feel like this is a generalization of `collect()`, tho. It's a monadic reduce, rather than a foldable reduce. [13:30:43.0000] I called it a generalisation because I could write "toArray" as `.collect(Array.prototype.concat, [])` or `.collect(Array)` depending on how we design the API [13:30:46.0000] (what's the structure that lets you walk the monad like that, but only produce single-value monads? Clearly something foldable-related...) [13:31:30.0000] I mean, yeah, but you can also write toArray with `reduce`, so the same argument applies. [13:31:52.0000] whether you think of programming in terms of monads or not [13:31:55.0000] sure, reduce is a generalisation of both of them [13:32:18.0000] I didn't plan to use the M word in this conversation lol :-P [13:32:50.0000] Haha, I used it because it's the right word for "I can write functions overthe values in this structure, but can't actually pull them out to look at" [13:33:43.0000] I really, *really* wish we didn't call them "monads", ugh. Makes them sound so foreign and weird. They're Chainables; you can chain them, just like Functors (ugh) are Mappables. [13:34:45.0000] So anyway, I've got an IO>. I can't pull out the individual array values, but I can return an IO for each. [13:35:13.0000] Well, hm. Can I. That's basically a Traverse, and IO isn't Traversable. [13:35:26.0000] michaelficarra: got a concrete example? ^_^ [13:35:44.0000] oh boy, off the top of my head? [13:37:21.0000] Hey, you proposed it, if you don't have a concrete use-case that's your own fault. ^_^ [13:37:41.0000] I think my takeaway here is that it would be nice if .collect() was an alias for .collect(Array) and you could also do .collect(Map), .collect(Set), etc. and that would call the Map/Set constructors or .of or .from methods [13:38:04.0000] I like to accommodate others who have strangers needs than me [13:38:07.0000] I'm just a bridge [13:38:08.0000] Not sure about how that works with async [13:38:26.0000] Domenic: It produces a promise for the constructed object. [13:38:39.0000] still think Promise.all makes more sense for the async collect case [13:38:41.0000] Domenic: should work fine [13:38:57.0000] So it collects into an... array? Then calls the Map() constructor? [13:39:05.0000] Like, what is the intermediate holding area [13:39:12.0000] More or less, yeah. [13:39:42.0000] we do have a common "entries" interface between all these items [13:39:55.0000] No generic "add one more item" protocol for the containers, so you have to do the whole thing at once and collect into an intermediate Array first. [13:40:23.0000] in the spec there's a AddEntriesFromIterable method [13:40:30.0000] which all the individual constructors use [13:40:44.0000] there could be some symbol that constructors expose to consume entries interfaces [13:40:56.0000] Like, would be more straightforward if they all had an `.addNext()` method that took an appropriately-shaped object (a value for Array and Set, a `[k,v]` pair for Map) matching each entry in their constructing iterators. [13:40:57.0000] or maybe the instance [13:41:12.0000] like Map.prototype[Symbol.addEntry] = Map.prototype.set [13:41:21.0000] Scope creep.... [13:41:25.0000] Maybe toArray() is simplest for now [13:41:26.0000] Then you can just build an empty on at the start, async-pull and add as you go, then finally resolve the promise with the completed object when you've drained the iterator. [13:41:36.0000] Hah. [13:41:53.0000] Or make collect() throw if called with more than 0 args so we can extend it in the future [13:41:57.0000] michaelficarra: Anyway, get the people you're bridging for to provide a concrete use-case so we can evaluate it. ^_^ [13:42:01.0000] (Array always being the default.) [13:42:22.0000] what would the internal makeup of collect be that using Array as a parameter works [13:42:39.0000] like calling with the final array? [13:43:15.0000] like if collect(Array) ~= Array(collect()) [13:46:01.0000] Yeah except Array constructor is broken so probably .from()? [13:47:08.0000] /me is gonna go watch Lonsdorf's lecture real quick. [13:47:49.0000] something interesting was Iterator.from [13:48:27.0000] if i do `Iterator.from({ next() {} })`, the idea was to push out something that has those methods and the correct prototype? [13:48:39.0000] like inheriting from both objects at once... [13:50:19.0000] It inherits from the correct prototype, unclear exactly how [13:50:26.0000] Probably it creates a wrapper that pulls [13:50:39.0000] Like the wrapper's next() calls the provided object's next() [13:51:01.0000] sounds useful [13:54:37.0000] devsnek: I was thinking it would pull the methods from the appropriate places (ideally Symbol-valued properties that identify generally useful concepts) [13:54:41.0000] (I'm talking about protocols) [13:56:12.0000] Domenic: anyway I do want to rename collect to `toArray` I think [13:56:34.0000] if that's what it does [13:56:56.0000] `Array.from(iterable)`, `iterable.toArray()` is a nice symmetry [13:57:04.0000] s/iterable/iterator/ I guess [14:05:12.0000] michaelficarra: Ohhh, I see, you just want a monoidal reduce() [14:05:19.0000] Not even a monadic one. [14:08:04.0000] Hm, Lonsdorf is playing some trickery here tho. In the transducer section they talk about `concat` as a reducer; there the signature is `Fa -> a -> Fa`. Then in the monoid section they pretend its signature is `Fa -> Fa -> Fa`. None of the reducer stuff uses monoids directly. [14:10:42.0000] i propose an implementation defined "use monadic" which overrides my proposal as needed [14:11:07.0000] But the "monoidal fold" operation is more traditionally written with a monoid-lifter and then the foldable of values. (And if you have a real Monoid thing, you don't need to specify the joiner or the empty value.) [14:11:27.0000] devsnek: (sorry, I'm responding backwards a bit.) [14:12:00.0000] no you're fine i'm just failing at resting pragma jokes [14:14:13.0000] So my point is, `Iterator([1,2,3]).collect(...)` wouldn't call the callback with an accumulator and `[1]`/etc, that's a different sort of method entirely. [14:14:17.0000] Unless I'm totally misreading. [14:16:00.0000] if it had a callback, i would hope it called it with the finished array [14:16:36.0000] i'm still unconvinced collect needs a callback (and to that end, changing it to toArray seems reasonable) [14:19:20.0000] yeah I guess it's Haskell's `mconcat`? [14:19:47.0000] my intuition before was that it was a MonadPlus but if we remove Monad, we're just left with a Monoid [14:25:04.0000] Yeah. So the signature you want is instead `iterator.collect(lifter)`, where `lifter` takes a value from the iterator and returns a Monoid wrapping that value. So `[1,2,3].collect(Sum)`, where `Sum` is a class implementing the three required monoid operations (`.of()`, `.empty()`, `.concat()`. [14:25:53.0000] `class Sum { constructor(val) { this.val = val; } empty() { return Sum(0); } concat(that) { return Sum(this.val + that.val); }}` [14:27:07.0000] And then if the values in the iterator are *already* monoids, you can call it with no args. [14:27:11.0000] I figured we could do it without an "of"/"pure" though, as I mentioned above [14:27:14.0000] But anyway, that's not .collect(). [14:27:49.0000] Not sure how you'd do it without the lifting operation. [14:28:06.0000] yeah me either [14:28:17.0000] Your suggested signature is basically providing the monoid operations directly, rather than just giving a class. [14:28:38.0000] I suggested both [14:28:52.0000] I don't care which one we pick [14:28:55.0000] Ah, didn't see the monoid-only one. [14:32:37.0000] Ah, and I guess we actually can't rely on the values already being monoids, since we don't know their type ahead of time, and thus can't select an empty value. [14:36:47.0000] the user needs to provide an empty [14:37:48.0000] Sure, if you're using a deconstructed monoid, where the function just takes all the bits itself rather than having them packaged into a pre-existing class. [14:38:02.0000] But then you're just reinventing reduce() directly, except less convenient. [14:39:20.0000] Because rather than the signature being `reduce((acc,b)=>acc, empty)`, you have `collect((monoid, monoid)=>monoid, empty, val=>monoid)` [14:40:08.0000] this seems like a scary api [14:40:22.0000] The main value in a monoidal reduce is that you can provide either (a) nothing, relying on the contents being monoidal, or (b) a lifter function only; because of type knowledge it automagically works correctly even when the iterator is empty. [14:40:36.0000] Can't do that in JS; monoids don't have as much justification. [14:40:49.0000] empty iterator is empty array [14:40:56.0000] like how map on an empty array is still safe [14:41:07.0000] devsnek: No, if your monoid is Sum, then empty iterator should be 0. [14:41:12.0000] If Product, should be 1. Etc. [14:41:39.0000] you mean [14:41:44.0000] if the iterator has stuff [14:41:47.0000] you want the starting value to be 1 [14:41:52.0000] otherwise you want the starting value to be 0 [14:41:55.0000] No. [14:41:59.0000] it depends on the operation [14:42:12.0000] then i don't understand what the existing reduce method is missing [14:42:17.0000] `arr.reduce((a, b) => a + b, x)` should have `x` be `0` [14:42:23.0000] but `arr.reduce((a, b) => a * b, x)` should have `x` be `1` [14:42:26.0000] etc [14:42:36.0000] yeah sure [14:42:53.0000] I mean, if you call `[Sum(1), Sum(2), Sum(3)].collect()`, you should get back a `Sum(6)`. But if you call `[].collect()`, you should get back a `Sum(0)`, *assuming the language knows you intend that to be an Array of Sums*. [14:42:59.0000] Since JS can't know that, you can't get that ability. [14:43:00.0000] is this about wrapping the initial value into the thing that reduces [14:43:18.0000] rather than them being separate args [14:43:19.0000] So you still have to pass in an empty value, and you've lost most of the reason to use monoids in the first place, versus just using reducers. [14:54:04.0000] I'd rather `[1, 2, 3][Symbol.iterator]().collect({ [Applicative.pure](a) { return { value: a }; }, [Semigroup.concat](a, b) { return { value: a.value + b.value }; }, [Monoid.empty]() { return { value: 0 }; } }).value` than do the reduction [15:00:23.0000] I'm... not sure how serious you are. Versus `[1,2,3].reduce((a,b)=>a+b, 0)` [15:01:58.0000] well it's not like I'm going to write those every time [15:02:54.0000] If you're pre-writing the class, you can prewrite `function summer(a,b) { return a+b; }` and then just call `[1,2,3].reduce(summer, 0)`. ^_^ [15:05:06.0000] (Also, pedantry: the necessary method isn't Applicative.pure, but rather Pointed.of; monoids have no reliance on Applicative, but this usage of them does rely on the type being Pointed.) [15:19:02.0000] the usefulness of Pointed on its own is contentious [15:20:27.0000] I would not support introduction of a protocol that just supported `a -> f a` because you can't get anything for free from just that protocol [15:20:29.0000] Sure, sure. Thus the pedantry. [15:20:59.0000] also, on the name pedantry for transducers [15:21:00.0000] (But it *is* weird to have a Monoid protocol that depends on part of the Applicative protocol for no clear reason.) [15:21:09.0000] it really is a pattern, not a particular fucntion or data structure [15:21:44.0000] I didn't re-watch Brian's talk, but I think he explains it in there actually [15:21:54.0000] did he go into recursion schemes in his talk? [15:23:02.0000] transducers are just the usage of a specialised recursion scheme: specialised to iterable structures and specialised to an algebra that is built up from composed functions for the one (Cons) constructor [15:27:31.0000] He only mentions transducers in the context I'm familiar with: functions that transform a reducer to other reducer. [15:27:44.0000] Thus the name. [15:28:41.0000] (I know "transduce" has the more general definition that's basically the same thing too, but it's usage wrt reducers in particular seems to mostly be a "transform"+"reduce" neologism pun.) [15:28:54.0000] /me perks up at the magic word [15:31:39.0000] that wasn't enough payoff in that mention of "pun" :-P