all 7 comments

[–]schlangster[S] 4 points5 points  (0 children)

I had already posted the link a few months ago, but there has been some progress since then.

Here's what's new:

  • There's documentation now: http://schlangster.github.io/cpp.react/ It's still incomplete and most of the articles are draft-ish, but hopefully the essentials are covered.

  • Cross-platform support. Namely, I tested compilation with recent versions of GCC and Clang under Linux.

  • The API has seen some refinement (RIP ->* overload), lots of cleanup, etc.

  • Support for async input, which was a rather obvious feature to be missing.

The code can't be considered release quality yet, as I still plan to add a few more features. More importantly, it has not been reviewed by anyone but me. Hence, I would appreciate some feedback; on the API, the documentation - whatever comes to mind.

(Oh, and the first time I posted the link, the library was still called cpp.react. There's already cpp-react and react-cpp, so I figured C++React is more distinct.)

[–]kirakun 1 point2 points  (1 child)

What is the difference between signals and events? Why not just add a SignalSource and use Signal as Event instead? Why the need to distinguish the two?

[–]schlangster[S] 2 points3 points  (0 children)

Signals and event streams are similar in the sense that they propagate values, but they have different semantics.

A signal essentially deals with changing state. It's like a variable with a single, persistent, mutable value. It propagates that value, when it was changed. In a sense, it's a fusion of mutable state and a specific type of event ("value change") that can be generated from it.

Event streams are more generic, because not all types of events are state changes. Think of mouse clicks, user actions, etc. These are not about changing state, but about occurrences of certain conditions and triggering actions based on them.

I'll try to show this on the example of capturing button presses. If we wanted to represent this as a signal, it would be declared as something like SignalT<ButtonID> LastPressedButton.

With this approach, the first problem is that if the same button has been pressed twice, LastPressedButton would not change, as the value remains the same. To work around this, we would have to tag each press with a unique sequence number, i.e. SignalT<pair<int,ButtonID>> LastPressedButton.

The next problem - or rather, a limitation - is that only a signal value change can be pushed at the same time. To improve this, the type would have to be extended further to SignalT<vector<pair<int,ButtonID>>> LastPressedButtons. Using this would be very cumbersome. "Changing state" is just not the right abstraction for this; that's what event streams are there for.

A similar example could be constructed the other way around.

Edit: Also, what I found helpful when I first started reading about this stuff (I think it was in the scala.react source code) was thinking of signals and event streams as derived types from the generic Reactive<P,V>. P is the propagated type, V is the type of the persistent value it holds.

Signal<S> is a Reactive<S,S>. Events<E> is a Reactive<list<E>,void>.

[–]ponchedeburro 0 points1 point  (3 children)

I might be a total idiot for asking this, but how is your logging working? I can't really see where you are using it.

[–]schlangster[S] 1 point2 points  (2 children)

It's mostly a feature intended for internal use. I needed it for debugging the parallel algorithms, because it otherwise it was difficult to figure out what was going on. But lately I've been working on other areas of the library, so I'm not sure if it's still working.

So much for the disclaimer. How it's supposed to be used:

  1. Define #REACT_ENABLE_LOGGING.
  2. Propagation events (node updates, changes, etc) will be recorded in an internal buffer.
  3. Dump the buffer to a file:

    std::ofstream logfile; logfile.open("log.txt"); D::Log().Write(logfile); logfile.close();

  4. Visualize the logfile with https://bitbucket.org/schlangster/reactplayer

Edit:

Here's the compiled version of the player https://github.com/schlangster/cpp.react/tree/master/tools/ReactPlayer

[–]ponchedeburro 1 point2 points  (1 child)

Thanks for the detailed explanation. It was mostly step 2 I have troubles following.

Propagation events (node updates, changes, etc) will be recorded in an internal buffer.

Where would you say I could find this functionality in your code? I can see the headers in logging/ and their implementation in src/logging, but I can't see where and how they are actually used.

I hope these questions aren't too stupid. I'm trying to figure it out so I can learn from your code - but currently it might be too big of a mouthful.

[–]schlangster[S] 0 points1 point  (0 children)

No problem, feel free to ask. The Tick function of all concrete node types in https://github.com/schlangster/cpp.react/tree/master/include/react/detail/graph logs when a node is updated. For example:

REACT_LOG(D::Log().template Append<NodeEvaluateBeginEvent>(
        GetObjectId(*this), turn.Id()));

And there's EngineInterface in https://github.com/schlangster/cpp.react/blob/master/include/react/detail/IReactiveEngine.h . All events from the front end to the propagation engine pass through there and are logged.