dumle icon indicating copy to clipboard operation
dumle copied to clipboard

A simple framework that I think it is similar to Imba!

Open limira opened this issue 5 years ago • 7 comments

Hi, I create an issue here because I don't have a reddit account and because you say that Doduo inspires by Imba. I implement a simple framework called Simi (inspired by Yew), and later I find out that it's similar to Imba (read my comment here). Some similarities I found between your ideas for Doduo and Simi:

  • Not care about storing tag name
  • Simi also has Create mode and Update mode
    • And update mode expect the nodes should be there already
  • Procedural macro to transforms code
    • And idea about implement control flow such as if (let), match, for (Simi already implemented these, I don't have plan to implement while).

But the way Simi generate code is different to your envision. If you want to see the code generated by Simi, you may try its simplest examples/counter and uncomment the //@debug (line 31) to see it.

I may read your ideas more careful later and come back to correct any misunderstand (my empty stomach make my eyes weary now :weary: )

limira avatar Mar 29 '19 04:03 limira

Simi looks really great! I'll archive this in favor of Simi. I haven't had enough time to look through all the code, so take this with a grain of salt, but the main differences I see that you could consider are:

  • Usage of a keyed list diff algo. I think the LIS crate I wrote would be great for Simi (version published to crates.io is older than git).
  • Bump allocation instead of on heap. Should be a small perf improvement.

axelf4 avatar Mar 29 '19 09:03 axelf4

I'll archive this in favor of Simi

It's very great if we can collaborate! If you want, I suggest you may want to play with Simi a little bit to see how you feel about it before any decision. Because Simi is already there (although still a WIP) and have some similarities with your ideas. Feel free to ask any question if I did not document (good) enough.

Usage of a keyed list diff algo. I think the LIS crate I wrote would be great for Simi

Simi does not support keyed list yet. But I am sure I will have a look at LIS when implementing it.

Bump allocation instead of on heap. Should be a small perf improvement.

After the first render, Simi try to directly update the current-only-virtual-DOM rather than rendering a new virtual DOM. Therefore, I think pump allocation is not suitable for Simi. But maybe it is suitable for keyed-list?

limira avatar Mar 29 '19 16:03 limira

I have done some experimentation in the zerosize branch, and came up with something that takes a quite different approach from Simi. Basically using zero-sized types and macro_rules instead of proc-macros. It is a little messy, and I'll see about cleaning up the code, but what do you think?

axelf4 avatar Apr 21 '19 19:04 axelf4

It's very interesting to see the very first steps of a new project (especially, building by a more experienced dev). Your work is far more Rusty than mine.

No thing from Imba, no bump allocation for now? Any plan to introduce/implement them? But from my understanding, currently you go with traditional virtual DOM (rerender the vDOM on every update then diff and patch), it make "The main distinguishing ideas are that we reconcile while building the virtual DOM" (quoted from README) impossible!?

I think you want to allow multiple UseStates (similar to component?) in an app? They are isolated to each other (no communication between them)?

I used to sprinkle arbitrary code inside a renderer. It's not a problem for a small app. But in a big app, I tend to lost in my own code. Therefore, Simi don't allow Rust code appear in its renderer (a renderer should focus on rendering, hence I never have to dive in the renderer to find codes that do non-render stuff). How do you think about this? For example, how to move this and/or this out of html!

limira avatar Apr 22 '19 16:04 limira

Thanks for taking a look!

currently you go with traditional virtual DOM (rerender the vDOM on every update then diff and patch), it make "The main distinguishing ideas are that we reconcile while building the virtual DOM" (quoted from README) impossible!?

Yes, it works differently from the draft in the README. But it is still incremental DOM like Simi/Imba. The difference from traditional virtual DOM (thinking seed, doduo, etc) is that building the VDOM is zero cost. That is because the html! macro turns, for example:

html! {
    <div>
        <button />
    </div>
    <img />
}

into (Child(div, button), img) which is a zero-sized type. Thus the compiler is able to, in theory, inline the whole reconciliation phase into something that could have been generated by the component! macro from Simi. Bump-allocation I still think is relevant both for this and for Simi, however as you said it gets harder when you only re-render the current component/UseState. I think dodrio solves that by having an arena of bump allocators available, which is something to look into in the future.

I think you want to allow multiple UseStates (similar to component?) in an app? They are isolated to each other (no communication between them)?

You could have multiple UseState but, while they are based on React's useState hooks, in Rust they become a lot less ergonomic. Definitely room for improvement.

Simi don't allow Rust code appear in its renderer (a renderer should focus on rendering, hence I never have to dive in the renderer to find codes that do non-render stuff). How do you think about this?

I am fine with it as long as it doesn't mutate any state. That said, for stuff like callbacks I think messages are the way to go, like how they are implemented in Simi. It's just that I think that it's out of scope for this small virtual DOM library.

axelf4 avatar Apr 22 '19 17:04 axelf4

The difference from traditional virtual DOM (thinking seed, doduo, etc)

Do you mean "(thinking seed, dodrio, etc)" :D?

Thus the compiler is able to, in theory, inline the whole reconciliation phase into something that could have been generated by the component! macro from Simi.

Wow, that's like magic! But I do not have enough knowledge (especially in Rust) to figure out! I can't wait to see a benchmark (and hope it goes well)! :D

they are based on React's useState hooks

It was not there when I learnt about React. I moved away from React for awhile. It's definitely on my to-read list (to try to understand what you want to do with UseState).

for stuff like callbacks I think messages are the way to go, like how they are implemented in Simi

Yeah, in the case that this happens, your crate may be a greate alternative, I may consider switching to it from Simi.


How about checking mismatched tags at compile time like this (you may want to paste the code into Rust playground to see how it works):

macro_rules! match_tag {
    // Unfortunately, this approach requires you to define a rule for each tag
    // So, for html tags, this requires more than 100 rules. How many are svg tags?
    (@match div div) => {};
    (@match span span) => {};

    (@match $open:ident $close:ident) => {
        compile_error!("Mismatched tags. See next error to find out where the mismatch occurs");
        // The next line forces error at the mitmatched close tag
        match_tag!($close);
    }
}

macro_rules! html {
    (<$open_tag:ident> $($tt:tt)*) => {
        html! { @tag $open_tag $($tt)* };
    };
    (@tag $open_tag:ident </$close_tag:ident>) => {
        match_tag!(@match $open_tag $close_tag);
    };
}

fn main() {
    html! { <div></span> };
}

limira avatar Apr 23 '19 07:04 limira

Do you mean "(thinking seed, dodrio, etc)" :D?

Nice catch! Should probably come up with a new name since doduo no longer fits.

I can't wait to see a benchmark (and hope it goes well)!

That would probably be a next step! I reckon it's not very fast at the moment, since it always has to walk the DOM tree, as DOM nodes aren't stored, but the Web IDL Bindings Proposal should reduce the overhead for free. Upcoming Rust features, such as specialization; const generics; and custom allocators, should also help.

Yeah, in the case that this happens, your crate may be a greate alternative, I may consider switching to it from Simi.

Don't say that yet - we haven't seen any proofs of performance. ;)

How about checking mismatched tags at compile time like this

That's a good idea. I looked at const functions to do that in a less hacky manner, but that functionality was not ready yet - unlike your solution.

axelf4 avatar Apr 25 '19 16:04 axelf4