[19:20] panesofglass So, virtual DOM
[19:20] panesofglass Did you say that formlets already does that?
[19:20] t0yv0 since i don't know exactly what vdom is
[19:20] t0yv0 i can't tell for sure
[19:21] t0yv0 but i know that formlets do use efficient dispatch of changes in a tree of widgets
[19:21] t0yv0 some application of "derivative" types, d/Tree = type Delta ..
[19:22] panesofglass General idea is that you have a bunch of DOM nodes created in the browser.
[19:23] panesofglass Using string templates and innerHTML is about the worst, perf wise, right?
[19:23] t0yv0 yeah, well first of all, let's lay performance aside for the moment :)
[19:23] panesofglass So, DOM templates have been all the rage, but they still generally replace large chunks of the DOM
[19:23] t0yv0 talking correctness, how does VDom manage identity? does it?
[19:24] t0yv0 there's a sweet fragment of HTML where identity does not matter
[19:24] panesofglass The idea of the virtual DOM is to use a lightweight representation of the DOM in memory and perform a diff to determine exactly what needs to change, then make only those few, select changes, if any.
[19:24] t0yv0 there it's easy to see how this would work
[19:24] t0yv0 but how do you do a diff once there're some opaque (exists state, .. ) pieces?
[19:25] t0yv0 also
[19:25] panesofglass I don't think it manages identity. Looking at mithril, I think it treats DOM nodes as values and does a structural comparison
[19:25] t0yv0 in, say, formlets, you don't need to perform any diff because you know what needs to change in the first place
[19:25] t0yv0 yeah
[19:25] t0yv0 if it doesn't manage identity, i think it's a mistake, or rather
[19:25] panesofglass are you saying that the whole content block in which a formlet renders is replaced, or that, say, a single attribute was all that needed to get updated, so you only modified that one attribute?
[19:26] panesofglass within the formlet dom, that is
[19:26] t0yv0 it's a good idea for a subset but you need MORE than that subset
[19:26] t0yv0 a formlet is actually a tree of sub-formlets
[19:26] panesofglass correct
[19:26] t0yv0 when change happens, only that thing that changed gets redrawn
[19:26] t0yv0 let me lookup the code for you, jas
[19:26] panesofglass http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/
[19:27] t0yv0 don't quote that guy to me, i have taken a dislike :)
[19:27] t0yv0 j/k
[19:28] t0yv0 something along these lines: https://github.com/intellifactory/websharper/blob/master/IntelliFactory.Formlet/Tree.fs
[19:28] panesofglass uh oh!
[19:28] t0yv0 i'm not saying it's perfect or even that it's that good
[19:28] t0yv0 but the basic idea of propagating changes to where they matter, this is very doable
[19:28] panesofglass how does Apply work?
[19:29] panesofglass I think this is similar. It walks the DOM applying the necessary changes?
[19:29] panesofglass Is that accurate?
[19:29] t0yv0 see, there's no DOM here
[19:29] t0yv0 :)
[19:29] panesofglass If so, I think that's equivalent.
[19:29] panesofglass (and probably better)
[19:30] t0yv0 when this is used by formlets to render, individual formlets remember their own pieces of dom, and they manage that
[19:30] t0yv0 the Tree type helps dispatch changes to the formlet that matters
[19:30] t0yv0 so the dom update happens locally
[19:30] t0yv0 at least that was the hope
[19:30] panesofglass nice
[19:30] t0yv0 Apply can be thought of giving a meaning to Edit<'T>
[19:31] t0yv0 Edit<'T> is an encoding of a transform of Tree<'T>
[19:31] panesofglass is it possible to use this to roll changes forward and back, e.g. undo/redo?
[19:31] t0yv0 so people say Edit<'T> is a "derivative" type from Tree<'T>
[19:31] panesofglass I see
[19:31] t0yv0 no it's not and here's where the big problem comes in
[19:31] panesofglass By memoizing Edit, I would expect I could get something that would allow me to undo/redo
[19:32] t0yv0 the big problem is, as we found out in practice, one cannot avoid or gloss over managing identity
[19:32] panesofglass Also, is this used for rendering piglets, or can it be used for that purpose?
[19:32] panesofglass what do you mean by identity?
[19:32] panesofglass and why is that important?
[19:32] t0yv0 actually i have no clue, tarmil is your guy on piglets :)
[19:32] t0yv0 so about identity:
[19:33] t0yv0 this is what we found to be most painful in practice, and i am still searching for a good way to deal with it, but here it is
[19:33] t0yv0 most libraries out there give you stateful objects, which is solid idea, it is about abstraction
[19:33] t0yv0 so you get (x : T), where T is an abstract type, and it is mutable
[19:34] panesofglass This sounds like the perfect topic for another of your brilliant blog posts.
[19:34] t0yv0 even if you are not using any frameworks, you already have that with plain browser
[19:34] t0yv0 for example, a simple box has state such as focus
[19:34] t0yv0 something that the user interacts with directly and changes
[19:34] t0yv0 now
[19:34] panesofglass ah
[19:35] t0yv0 if we had a primitive, that for any abstract type T, "serialized" its internal opaque state, and was able to restore it
[19:35] t0yv0 like,
[19:35] panesofglass the idea behind the virtual DOM is to by-pass this issue, at least from the developer's point of view.
[19:35] t0yv0 if everything had toJSON/fromJSON
[19:35] t0yv0 then it would be perfect
[19:35] t0yv0 it would allow this kind of techniques to be really successful
[19:35] t0yv0 however, in the real world, i don't think you CAN bypass the isse
[19:36] panesofglass the idea behind the VDOM is to separate the render state from the event state
[19:36] t0yv0 how?
[19:37] t0yv0 how do you diff a tree of states where some of the states are opaque abstract types?
[19:37] t0yv0 it seems to me it can't be solved in general
[19:37] t0yv0 but maybe i just don't know vdom :)
[19:39] t0yv0 note a similar issue comes up with defining someting like formlet "many" combinator: say you have a logical
model 'T, and a renderer that is T -> UI
, how do you lift it to a list?
[19:39] panesofglass I look forward to learning. :)
[19:39] t0yv0 more appropriately, you have a Signal<'T>, Signal<'T> -> UI, and how do you make Signal<list<'T>> -> UI ?
[19:39] panesofglass Oh, I see the issue wrt "tree of states"
[19:39] t0yv0 in this kind of combinators, you need a diff, you also need a policy on identity
[19:39] panesofglass React, mithril, etc. render the tree, then do the diff
[19:40] panesofglass then apply the diff results to the actual DOM
[19:40] panesofglass on the requestAnimationFrame cycle
[19:40] t0yv0 this is under-specified. for example, if on step 1 we had items [Apple, Orange], and on step 2 we had [Apple], and on step 3 you have [Apple, Orange] again, okay?
[19:41] panesofglass What's the Signal<'T>?
[19:41] t0yv0 you have a difff-er, and a renderer. now, will your renderer associate identially same DOM nodes to Apple/step1 or Applye/step3?
[19:41] panesofglass Is that an event?
[19:41] t0yv0 i'm talking loosely here, some kind of changeable value
[19:41] panesofglass oh, okay
[19:42] panesofglass ah, I see your point
[19:42] t0yv0 so for example, on reasonable policy would be: Apple gets preserved between steps 1 and 2, so we keep the same DOM tree for it
[19:42] t0yv0 but we remove Orange tree
[19:42] panesofglass I haven't dug deep enough to know the details
[19:42] t0yv0 so we re-create Orange tree again on step 3
[19:42] panesofglass but I think it's a string match
[19:42] t0yv0 but here we have a problem, if Orange tree had been modified by the user and we forgot to capture this change
[19:42] panesofglass maybe
[19:42] panesofglass I really don't know
[19:42] t0yv0 :)
[19:43] t0yv0 sorry, i must be a bit overwhelming
[19:43] t0yv0 i'm just really curious what React would do in such an example
[19:43] panesofglass I think you are right about Apple, Orange -> Apple -> Apple, Orange
[19:43] t0yv0 i think for me the bottom line is, that it might be useful to allow ignoring identity sometimes, but the developer should have access to managing it in general
[19:43] panesofglass The final Orange and the first Orange would not be related
[19:43] panesofglass though they may appear identical
[19:43] t0yv0 y
[19:44] t0yv0 another plausible policy for this combinator would be to memoize and hide these nodes
[19:44] t0yv0 so it saw Orange in step 1, it rendered it; on step 2 it simply hides the rendered stuff; on step 3 it re-appears
[19:44] panesofglass The idea I had from it is that it is similar to snapshots in time
[19:44] t0yv0 y
[19:44] panesofglass You don't care about identity, just the snapshot
[19:45] t0yv0 that'd be awesome
[19:45] t0yv0 just one problem -
[19:45] t0yv0 you can't snapshot dom nodes, can you?
[19:45] panesofglass of course, there are always problems. :)
[19:45] t0yv0 no i mean i would be seriously excited about this if
[19:45] t0yv0 there was a way to snapshot all relevant state from the dom nodes
[19:45] t0yv0 and i actually don't know. is there?
[19:46] t0yv0 we can obviously observe if a textbox has focus or not, and record that
[19:46] t0yv0 does it generalize?
[19:46] t0yv0 another thing is - almost all 3rd party libs WebSharper works with
[19:46] t0yv0 this would not be possible
[19:46] t0yv0 because they by design use abstract types that mutate themselves
[19:46] panesofglass I think because tools like React control everything they manage, they would break if you used, say, jQuery to modify something in the DOM controlled by React
[19:46] t0yv0 definitely
[19:46] panesofglass is that what you are trying to avoid?
[19:47] t0yv0 they'd also not be able to render a jQuery UI widget inside a React widget
[19:47] t0yv0 don't know..
[19:47] panesofglass I don't think focus would be important in this case.
[19:47] panesofglass Just the markup
[19:47] panesofglass but I see what you are saying now
[19:47] panesofglass perhaps that is important
[19:47] panesofglass I don't know
[19:47] t0yv0 to that i can for sure say, no, focus IS imporant
[19:48] t0yv0 you see, we went through these months and months of bugfixing :)
[19:48] panesofglass would be interesting to see how that is managed
[19:48] t0yv0 the hard-learned lesson was that you couldn't (at least at that time) casually treat dom state as purely functional
[19:48] panesofglass Here's the build function in mithril, which is likely a much more limited form of what React does: https://github.com/lhorie/mithril.js/blob/master/mithril.js#L35
[19:48] t0yv0 so we introduced some identity management into formlets, etc
[19:48] panesofglass I believe this is part of where things happen
[19:49] t0yv0 hm,, ugh what code :)
[19:50] panesofglass well, it's javascript, what did you expect? ;)
[19:50] t0yv0 yeah
[19:50] panesofglass glad it's not asm.js :D
[19:50] t0yv0 afaik it doesn't do what i'm talking about --^
[19:50] t0yv0 we have some similar shit in formlets i think
[19:50] t0yv0 the builder for the DOM
[19:50] panesofglass lol
[19:51] t0yv0 that tries to do caching, and this stuff
[19:51] panesofglass interesting
[19:51] t0yv0 it's probably not very good, but the idea is similar
[19:51] panesofglass so you are saying W# already does the DOM diffing
[19:51] t0yv0 i just think in general it does not work
[19:51] t0yv0 we don't do DOM diffing but we do incremental DOM manipulation
[19:51] panesofglass okay
[19:51] t0yv0 think about it, why do you need diffing? you only need diffing if you structure your code with functions that are not really functoins
[19:52] t0yv0 so you have, val f : Model -> VDom
[19:52] panesofglass so you apply only actual, changes to the DOM, not just the re-rendered block of formlet markup?
[19:52] t0yv0 and then you need diff (f m1) (f m2)
[19:52] t0yv0 if you structured your renderer as something with more structure than a function
[19:52] panesofglass brb
[19:52] t0yv0 then you won't need diff
[19:52] t0yv0 ok
[19:55] t0yv0 when you're back, do i have your permission to publish the chat log? thx
[20:23] panesofglass so ... right back was stretching it.
[20:23] panesofglass you have my permission to make me look stupid. I.e., yes. ;)
[20:25] t0yv0 that's still publicity hehe
[20:25] t0yv0 thanks
[20:26] t0yv0 i was just trying to say that diff function is necessary only if you insist on describing a transform from Model type to your VirtualDOM or something as a function
[20:26] t0yv0 if you use more structure, e.g. applicative or something, then the need goes away, e.g. you implicitly do the diff/change propagation in the combinators
[20:26] t0yv0 the syntax gets ugly though, of course
[20:27] t0yv0 i am writing a quick blog post. the other nasty thing is how this interacts with higher order dynamic combinators, especially something like monadic bind
[20:28] t0yv0 there is this nice little language called Elm
[20:28] t0yv0 they do a brave right thing and simply outrule monadic bind, there's some kind of stage separation
[20:29] t0yv0 the author even says in the thesis - hey, Signal (Signal t) -> Signal t
has been so notoriously difficult
to get tight, that we'll just prohibit it. He then designs a type system where you just can't construct anything like that
[20:29] t0yv0 and everything remains pleasant. it's a nice take on it
[20:29] t0yv0 s/get tight/get right/
This doesn't help me. I don't understand the requirement to lift to
Signal<'T> -> UI
.Let's say I've requested the page, and the following content is rendered into an empty DOM node:
Now suppose I want to, on a double-click, toggle the
contenteditable
attribute on the Age<div>
. The event triggers another render, which produces:(Aside: is it possible in WebSharper to just add the contenteditable attribute without setting a value?)
This render is compared to the previous render, so the only change to the DOM at this point is to add the
contenteditable
. React will generate this UI update (wherecomponentDiv
is its top-level element):It seems that React simply performs mutations against the DOM, so any other stateful values such as
:focus
, etc. remain un-affected for nodes that remain in the UI. Obviously, if you remove a node, it will no longer have state within the DOM, but I don't imagine you would want that.Another thing React does is batch DOM updates so that many, subsequent changes get merged into a single update, I believe on the
requestAnimationFrame
cycle.In your example above, it seems that the
Signal<'T>
would bump value changes for all properties of the'T
, which is not necessary. Also, I don't understand why you note "Problem: requiresDiff : UI -> UI -> Delta
for efficiency." Why is that a problem? I would expect something else to be responsible for executing the diff and then creating and applying the DOM mutations, not a lifted version of theRender
function.