Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cyclejs vs mercuryjs #49

Closed
nwmcsween opened this issue Dec 21, 2014 · 13 comments
Closed

Cyclejs vs mercuryjs #49

nwmcsween opened this issue Dec 21, 2014 · 13 comments

Comments

@nwmcsween
Copy link

It seems mercury is a more functional approach, cycle (from a glance) implements MVI but is not unidirectional (M and I interact). Clarification is welcome as well as key differences.

@staltz
Copy link
Member

staltz commented Dec 23, 2014

MVI is a unidirectional approach, there is arrows only in one direction and they form a Cycle. That's at the core of this framework.

Otherwise I'm not really familiar with mercury to point out the differences. Its documentation is very scarce and I can't see an obvious MV* architecture there.

@oren
Copy link

oren commented Jan 3, 2015

Mercury is immutable DAG (Directed acyclic graph).

videos

  1. NPM-style Frontend - http://youtu.be/8w0_Xw7PPFQ
  2. Unidirectional JavaScript - http://youtu.be/RLAjMeR8898
    Content from video: https://github.com/Raynos/forwardjs2014-talk/blob/gh-pages/content.md
    Slides from the video: http://raynos.github.io/forwardjs2014-talk/

Blog post about unidirectional apps and mercury: https://gist.github.com/alexmingoia/4db967e5aeb31d84847c

Feel free to ask questions here or in #virtualdom on freenode.
@Raynos is behind it and can share more details.

I started playing with Mercury and don't have a real world experience with it.
I am interested in the difference between Mercury, Cycle and Mithril so if you have good links or insights please share them.

I am not familiar with Cycle or Mithril, all I know is that Cycle is using reactive approach (RxJS) whle Mithril is interactive (something similar to view.update() inside a model etc). I believe that Mercury is also interactive but I might be wrong.

@staltz
Copy link
Member

staltz commented Jan 3, 2015

all I know is that Cycle is using reactive approach (RxJS) whle Mithril is interactive (something similar to view.update() inside a model etc).

That's a good way to describe it. Mithril has a very simple MVC (interactive, specially through the Controller) API. Cycle is completely reactive, using MVI.

I don't grok Mercury that well, it has too many parts. Maybe one clear difference is that architecture with Cycle is a directed cyclic graph, while Mercury has no graph cycles.

@Raynos
Copy link

Raynos commented Jan 3, 2015

Mercury is very component oriented at the root of it. Generally you write applications like

For example your simple.js ( https://github.com/staltz/cycle/blob/master/examples/simple/simple.js ) example is implemented as

var hg = require('mercury');
var h = require('mercury').h;

function Foo(initialState) {
    return hg.state({
        bars: hg.array(initialState.bars, createBar],
        channels: {
            addBar: Foo.addBar
        }
    });

    function createBar(x) {
        return hg.struct({
            id: hg.value(x.id),
            bar: hg.value(x.bar)
        })
    }
}

Foo.addBar = function addBar(state) {
    state.bars.push({
        id: 2,
        bar: Math.round(Math.random() * 1000)
    });
};

Foo.render = function render(state) {
    return h('div', state.bars.map(renderBar))

    function renderBar(bar) {
        return h('div', {
            'attributes': {
                'data-foo-id': bar.id
            },
            'style': {
                'margin': '10px',
                'background': '#ececec',
                'padding': '5px',
                'cursor': 'pointer',
                'display': 'inline-block'
            },
            'ev-click': hg.send(state.channels.addBar)
        });
    }
};

function main() {
    hg.app(document.body, Foo({
        bars: [{ id: 2, bar: 135 }]
    }), Foo.render);
}

Some of the core ideas are:

  • your entire view is a single complex vtree
  • your entire view state is a single complex immutable object.
  • your rendering function is pure, it takes just the view state.
  • you declare all user input as channels up front in your view state.
  • the view state supports cursors, you can nest components in components.

Mercury is unidirectional because:

  • A DOM event triggers a value to be send to a channel
  • The listener for the channel updates the view state
  • An update to the view state triggers a re-render
  • A new vtree is created
  • diff() and patch() update the DOM.

See more about life cycles here ( https://github.com/Raynos/mercury/blob/master/docs/life-cycles.md ).

Mercury is also a hybrid of functional and imperative, the rendering logic is functional but the updating logic has an imperative updating interface (backed by a stream of immutable objects under the hood).

This gives you an FRP style application written in a way that still feels like its javascript

@Raynos
Copy link

Raynos commented Jan 3, 2015

I also moved that comment here ( https://github.com/Raynos/mercury/blob/master/docs/introduction.md ) so other people have an easier time and @staltz can redirect them there :)

@staltz
Copy link
Member

staltz commented Jan 3, 2015

Thanks, overall good summary of Mercury. I wouldn't probably call it a DAG, because Foo.render has 'ev-click': hg.send(state.channels.addBar) which closes the loop from vtree to event channels, hence cyclic. But that's not a problem, I believe all three Mercury, Cycle, and Flux follow the same circular-unidirectional approach.

your entire view state is a single complex immutable object.

That shows a difference between Mercury and Cycle. "View states" in Cycle are called Models, and you can have multiple of them, with interdependencies (even circular dependencies).

your rendering function is pure, it takes just the view state.

Cycle and Mercury are basically the same here, although recently Cycle added support for custom elements, which means React-like components with internal state. I would assume Mercury has the same, https://github.com/Raynos/mercury/blob/master/docs/mercury-component.md, is that correct @Raynos? In other words, both frameworks encourage pure rendering, but allow hidden impure rendering when necessary.

@staltz
Copy link
Member

staltz commented Jan 3, 2015

Also, about this:

Mercury is also a hybrid of functional and imperative, the rendering logic is functional but the updating logic has an imperative updating interface.

I could say, similarly, that Cycle is a functional and reactive hybrid, with some impure shortcuts sometimes. But, Erik Meijer doesn't recommend using the term "mostly functional".

@Raynos
Copy link

Raynos commented Jan 3, 2015

Its not cyclic. Because there are no mutable dependencies.

  • The DOM is only mutated by virtual-dom
  • Your view cannot mutate your model. It can only read.
  • Your model cannot generate events, it can only read.
  • Your events come directly from the DOM in dom-delegator

You must remember that a channel is just a plain data structure.

The closing of the loop happens inside the framework. This is similar to how elm closes the loop inside the runtime.

the virtual-dom and dom-delegator machinery will close the loop for you, but that is completely external to your application, you should see mercury as being a runtime and you send messages to it and it sends messages back to you, your application has a client<->server relationship with the DOM through mercury.

@Raynos
Copy link

Raynos commented Jan 3, 2015

@staltz

both frameworks encourage pure rendering, but allow hidden impure rendering when necessary.

Mercury is pure. The virtual-dom module is pure. There is no hidden impure rendering.

The only thing that exists is that multiple things can write to the DOM. It's not just virtual-dom writing to it. This means that because we choose DOM as the rendering target and do not have unique ownership over it, there is effectively transient state in that DOM, for example <select> has transient state build into it because of the way the DOM works.

Mercury does not encourage any kind of impure rendering. Mercury components themself are actually a way to compose models in a tree, the mercury component system really allows you to compose view state, not rendering.

@staltz
Copy link
Member

staltz commented Jan 3, 2015

You must remember that a channel is just a plain data structure.

Ok, that explains a lot. So, yes, Mercury apps are a DAG.

both frameworks encourage pure rendering, but allow hidden impure rendering when necessary.

I was referring to the transient state that you mentioned with <select>. Through Cycle custom elements, you can make your own <myelement> with transient state just like <select> has. Does Mercury have the same through Mercury components?

The DOM is only mutated by virtual-dom

and

The only thing that exists is that multiple things can write to the DOM. It's not just virtual-dom writing to it.

Isn't that contradictory?

@Raynos
Copy link

Raynos commented Jan 3, 2015

Isn't that contradictory?

I meant that the only thing that mutates the DOM in your application is virtual-dom

Where as the latter statement means that because of reasons multiple things write to the DOM including your application and the browser itself

@staltz
Copy link
Member

staltz commented Jan 3, 2015

Yes, understood. And the same happens in Cycle, of course

@Raynos
Copy link

Raynos commented Jan 3, 2015

Does Mercury have the same through Mercury components?

mercury components have nothing to do with custom elements.

In cycle you mentioned you can multiple models. In mercury there is one big fat view state tree.

The way to conceptually have the nice modular seperation of multiple models is to use mercury components. mercury components are a way of seperating your big fat view state tree into many smaller view state trees and then finally composing them into a big tree.

Mercury components are a lot more about how do I logically seperate parts of my application and a lot less about how do i share re-usable units in a framework-agnostic way (custom elements).e

That being said you can use a mercury component for something that is application specific like MyNavigationBar or for something that is generic like TableLayout

@staltz staltz closed this as completed Feb 12, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants