GithubHelp home page GithubHelp logo

yarikth / ureact Goto Github PK

View Code? Open in Web Editor NEW
154.0 5.0 9.0 2.28 MB

Functional reactive programming library for c++

License: Boost Software License 1.0

CMake 7.49% C++ 90.09% Makefile 0.60% Shell 0.14% Python 1.68%
c-plus-plus cross-platform header-only cpp cpp17 c-plus-plus-17 frp-library functional-reactive-programming frp

ureact's Introduction

µReact

Linux Windows MacOS CodeQL codecov

Standard Type GitHub license download Docs GitHub Releases PRs Welcome

µReact is an open-source header-only functional reactive programming library for C++17.

❗️ This library is a work-in-progress. It should not be considered release quality yet and its API might still change.
However, it works perfectly fine and can be already used with small future changes in mind.
Feedback is strongly required and appreciated to stabilize the API and achieve the first major release.

Documentation

Features

  • Update minimality: nothing is re-calculated or processed unnecessarily
  • Glitch freedom: no transiently inconsistent data sets
  • Externally synchronized (not thread-safe) by design: it allows not to pay for what you don't use and to have very determined consistent behaviour
  • Ease of use: small self-contained single header code base, no external dependencies, permissive Boost Software License license
  • Really easy to get started: it's just 1 header file
  • Reliability: the library has an extensive set of tests
  • Portability: continuously tested under Windows, MacOS and Ubuntu using MSVC/GCC/Clang
  • Clean warning-free codebase even on the most aggressive warning levels for MSVC/GCC/Clang
  • Doesn't pollute the global namespace (everything is in namespace ureact) and doesn't drag any headers with it

Examples

Basic usage (run)

#include <ureact/signal.hpp>
#include <ureact/adaptor/lift.hpp>
#include <iostream>

int main() {
    ureact::context ctx;

    // Declaring reactive variables. We can reassign their values later
    ureact::var_signal<int> b = make_var( ctx, 1 );
    ureact::var_signal<int> c = make_var( ctx, 2 );

    // Defining reactive signal using overloaded operator
    // Its value will be updated each time its dependencies are changed
    ureact::signal<int> a = b + c;

    std::cout << "a (init): " << a.get() << "\n"; // 3

    // Assign a new value to 'b'. Value of 'a' is recalculated automatically
    b <<= 10;
    std::cout << "a  (new): " << a.get() << "\n"; // 12
}

License

This software is licensed under the Boost Software License 1.0:

Copyright © 2014-2017 Sebastian Jeckel

Copyright © 2020-2023 Krylov Yaroslav

Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:

The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


This software started out as a fork of the cpp.react by Sebastian Jeckel ([email protected]), BSL 1.0 licensed.

Used third-party tools

The library itself consists of a single header file licensed under the Boost Software License license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!

Contact

If you have questions regarding the library, I would like to invite you to open an issue at GitHub. Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate.

ureact's People

Contributors

alexezeder avatar yarikth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ureact's Issues

Support dumping dependency tree in dot format

Context should have some methods to dump debug info into the specified stream.
Possible info that can be dumped:

  1. type of the signal value (need some code to support stringify names of the types)
  2. value of the signal
  3. name of the react node (need to optionally pass on node creation)
  4. group of the signal? For e.g. all signals of one object can be grouped under some id

Consider changing name of the library

Description

As 00jknight said using special character for the library name is not a great idea:

Now, the title, using a special character like that makes the library far harder to search for and splinters the content between 'uReact' and 'µReact'. This is form over function and is a bad choice.

When I worked on the documentation, I also constantly deals with a special character problem, because I had to find a name somewhere to copy from.

Before version 1.0 changing of the library name is possible. Need to think about a better name.

For example it can be "do.react" or "do.react.cpp". With namespace do doo (ups!, reserven name...) and header path doo/react.hpp. Alternative - du.react. Sounds the same but shorter. But du.context du.signal and du.observer looks much less obvious than ureact.context or ureact.observer. So, name namespace after a file, not a folder? Isn't it form over function again?

Extra information

  • µReact version: 0.1.0

Refactor operators code

  • Add tests that check all the versions of operations.
  • Check the return type validity.
  • Check return value validity.
  • Move most of the operators' code out from the macros.
  • Check operators' priority.
  • Understand optimizations behind temp_signal and test if it works correctly.
  • Support operator <=> if c++20 is detected.
  • Support constexpr if possible and meaningful.
  • Support noexcept(bool) if possible and meaningful.
  • Check behaviour if an exception is thrown from operators. (maybe noexcept is strictly required)
  • Support nodiscard if possible and meaningful.

Make CMakeLists.txt ready to release

Current CMakeLists.txt is not ready to be used. Need some work to prepare it.
TODO:

  • setup install settings
  • support add_subdirectory usage (test if is the main project, disable tests and examples if not)
  • make sure all variables and options have prefix UREACT_

make sure all variables and options have prefix UREACT_

To make sure about the name of the options:
cmake -LA . | awk '{if(f)print} /-- Cache values/{f=1}' | grep -v '^CMAKE_' | grep -v '^ProcessorCount_'

Sample output:

build_examples:BOOL=ON
build_tests:BOOL=y

Need to add such a check in the Makefile as part of the repository sanity check.

Try to support transparent usage of operators

I would like to make the following code possible:

ureact::var_signal<int> a = make_var(&c, 1);
ureact::var_signal<int> b = make_var(&c, 1);
if( a < b ){
}else if( a > b ){
}else if( a == b ){
}

a = a + b;
a += b;

The main difference with the current usage is the absence of the .value() method calls.
a = b + c is much clear than a.set_value( b.value() + c.value() )

But now operators are overloaded to make easy signals creation. So need to investigate what can be done with it.

Name template arguments properly

Now error listing is very sexy:

D:\a\ureact\ureact\include\ureact/detail/var_signal.hpp(35,25): error C2059: syntax error: 'template' [D:\a\ureact\build\examples\example_complex_signals_v3.vcxproj]
          with
D:\a\ureact\ureact\include\ureact/detail/var_signal.hpp(82): message : see reference to function template instantiation 'void ureact::detail::var_signal_base<S>::set_value<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>(T &&) const' being compiled [D:\a\ureact\build\examples\example_hello_world_operators.vcxproj]
          with
          [
              S=std::string,
              T=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
D:\a\ureact\ureact\include\ureact/detail/var_signal.hpp(82): message : see reference to function template instantiation 'void ureact::detail::var_signal_base<S>::set_value<int>(T &&) const' being compiled [D:\a\ureact\build\examples\example_complex_signals_v3.vcxproj]
          with
          [
              S=int,
              T=int
          [
D:\a\ureact\ureact\include\ureact/detail/var_signal.hpp(82): message : see reference to function template instantiation 'void ureact::detail::var_signal_base<S>::set_value<int>(T &&) const' being compiled [D:\a\ureact\build\examples\example_changing_multiple_inputs.vcxproj]
          with
          [
              S=int,
              T=int
              S=int,
          ]
              T=int
          ]
          ]
          ]
D:\a\ureact\ureact\include\ureact/detail/var_signal.hpp(82): message : see reference to function template instantiation 'void ureact::detail::var_signal_base<S>::set_value<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>(T &&) const' being compiled [D:\a\ureact\build\examples\example_hello_world_operators.vcxproj]
          with
          [
              S=std::string,
              T=std::basic_string<char,std::char_traits<char>,std::allocator<char>>

T, S, S, T... It's impossible to debug.

Add [[nodiscard]] attribute to prevent misuse of the library

Description

I typo var_signal assign operator (b << 10; instead of b <<= 10;) and there were no errors or warnings, while the code behaves unexpectable. Need to add a nodiscard attribute to all meaningful places to prevent such errors.

Extra information

  • µReact version: 0.1.0
  • Operating System: Any
  • Compiler+version: Any

Run make pretty_check on CI

Description

Now we have support.yml workflow. It's an ideal place to perform pretty check step.

Extra information

  • µReact version: 0.1.0

Add `modify_result`

Description

Currently, modify method takes a void(T&) function and value considered changed regardless it actually changed or not.

Maybe it's a good idea to use observe's approach with passing either void(const T&) or observer_action(const T&) functor.

Extra information

  • µReact version: 0.1.0

Add semantic versioning

Need to make the first alpha release.

The version number should be in CMakeLists.txt and in the library headers.

Add arithmetic priority test

Something like

    ureact::context ctx;

    auto _2 = make_var( &ctx, 2 );
    
    auto result = _2 + _2 * _2;
    CHECK( result.value() == 6 );
    
    auto result2 = (_2 + _2) * _2;
    CHECK( result2.value() == 8 );

Test integration ways described in integration.md and fix them

Description

Currently, the integration ways described in integration.md are not tested, so they might be incorrect.

  • Need to add a testing mechanism
  • Additionally, it would be better to move integration.md near this test code
  • Packaging testing should be added in github actions
  • µReact version: 0.1.0

Add development documentation (repository support)

Description

Additionally to contribution guides, it would be good to write an overview about repository support stuff. How it works and how to add other automatization points.

Extra information

  • µReact version: 0.1.0

Prepare documenatation

The original project has a lot of useful documentation. Especially
Introduction to C++React that is a good candidate for the main readme and Dataflow model that describes implementation details that are useful for library users.

I think that it's better to start with the markdown documentation. At least it's easier to read and write on Github.

An example of clear markdown documentation can be found at doctest.

Support lazy evaluated calculation graph

Description

It would be useful to introduce lazy calculation trees, so following code would be possible:

context::context ctx;
auto a = ctx.make_var( 1 );
auto b = ctx.make_var( 2 );
auto c = ctx.make_var( 3 );
ureact::signal<MyYearlyReport> report = make_lazy_signal( with(a, b, c), &make_yearly_report );

cout << report.is_dirty() << "\n"; // true. There is no value yet
cout << report.value() << "\n";
cout << report.is_dirty() << "\n"; // false. Value is calculated and there were no changes in dependencies
a <<= 10;
cout << report.is_dirty() << "\n"; // true. Current value is no longer actual. Some of the dependencies are changed

Additional note: changes amount or just token could be also introduced. It can be sent to external sources, so externals can understand does their cached value actual or not. But this can be useful even out of lazy evaluation context, so should be moved to a separate issue.

Introducing lazy evaluation is basically supporting demand-driven (pull) sampling of reactive behaviours. Unfortunately, this is not easily combined with current data-driven (push) evaluation. It's a question of how to do with observers attached to such nodes. It's a question if normal nodes can be attached to a lazy node and how to operate in this case. And if events composing would be introduced they are also hardly compatible with lazy nodes.

Extra information

  • µReact version: 0.1.0

Reverse engineer existing code

Need to research existing code to comprehend it and be able to maintain it.
TODO: make a list to research
It seems that it's a good idea to write autotests for internals to comprehend them.

Support ureact::const_signal

It would be convenient to make the following code possible

std::string makeExprStr(int a, const char* op, int b)
{
    return std::to_string(a) + std::string(op) + std::to_string(b);
}

make_signal(with(a,"+",b), makeExprStr);

Instead of

std::string makeExprStr(int a, const char* op, int b)
{
    return std::to_string(a) + std::string(op) + std::to_string(b);
}

make_signal(with(a,b),
        []( const int lhs, const int rhs )
        {
            return makeExprStr(lhs, "+", rhs);
        });

The key point here is the possibility to pass some random constants in signal packs (and maybe even in the make_signal function, but it's a weak idea). It still can be done with intermediate lambda, but it's more ugly and verbose.

Try to support observers that pass both old and new values if applicable

Possible usage

ureact::context c;
ureact::var_signal<int> a = make_var(&c, 1);

observe(a, [] (std::optional<int> old_value, std::optional<int> new_value ) {
    std::cout << "'a' changed from " << (old_value ? *old_value : "Unknown")
                           << " to " << (new_value ? *new_value : "Unknown") << std::endl;
});

Add a code reference

Description

Need to provide a full list of interface classes and their documentation. Maybe it would be a good idea to additionally summarize pluralism points (which methods and classes are interchangeable and act completely the same).

Such documentation allows thinking about renaming classes and other stuff.

Documentation or at least the textual part of it should be automatically extracted using oxygen. It would be constantly outdated otherwise.

Extra information

  • µReact version: 0.1.0

Add test to check if minimal version CMake can process CMake scripts without errors

Description

Currently, CMake scripts (both CMakeLists.txt and *.cmake) set some version in cmake_minimum_required, but on CI these scripts are executed on arbitrary cmake versions. As a result, if we try to execute cmake scripts on exactly the minimal cmake version, then there are no guarantees that it works. Need to add automatic tests on GitHub actions that will ensure that all is fine.

Extra information

  • µReact version: 0.1.0

Library should have exception safety guaranty

Library internals shouldn't be broken in the case when the user-defined observer function, signal calculation function, etc throws an exception. Need to make more or less sane behaviour in such a case.

For example, it would be a good idea to restore the state before the transaction was requested. It would be hard or impossible in case of using the modify() method.

At the very least library should provide more or less useful debug information to say where the problem has happened and why.

Need to support recursive transactions

It would be useful to support recursive transactions. In such a case only 1st transaction would be a real transaction, while inner transactions should just call their functions.

Now only a boolean flag is used and in the case of recursive transactions, code is silently broken (action performs as soon as the inner transaction is done).

Improve public headers includes

Now the public headers are a mess. Need to make one or two public includes and hide all other code inside details. As a result, users would clearly understand which headers they should include. Maybe the only usage of ureact namespace without detail should be done there. Also, version number would be added there.

Take movable context idea from cpp.react

Description

Currently, contexts aren't movable. But they quite easily can be made one, using cpp.react's an approach for Group. When Context itself is merely a pointer that can be copied, while the only thing that actually matters is reactive_graph.

It was requested on reddit. Not strictly, but it is nice to have feature.

Extra information

  • µReact version: 0.1.0

Consider providing a default context as a singleton

Description

Currently, context is required even for trivial cases when there are no other contexts used. It would be a good idea to provide some "contextless" set of functions that allow writing less verbose examples without passing the context here and there.

Default context could be an optional feature that can be disabled using macro. Making it thread-local can be also considered.

ureact::var_signal<int> b = ureact::make_var(1);
ureact::var_signal<int> c = ureact::make_var(2);
ureact::signal<int> a = b + c;

std::cout << "a (init): " << a.value() << "\n"; // 3

b <<= 10;
std::cout << "a  (new): " << a.value() << "\n"; // 12

Extra information

  • µReact version: 0.1.0

Add -stdlib=libc++ configuration for clang builds

Description

Need to add -stdlib=libc++ configuration for clang builds. It would be enough to make such a configuration for Ubuntu only.

CXXFLAGS=-stdlib=libc++

Extra information

  • µReact version: 0.1.0

Convert examples to tests

Tests should become the first and only example code for the library. They should be readable and explanatory for the newcomers.

Consider rewriting pretty.sh to cmake script

Description

Currently, pretty.sh is a lonely bash script within the whole repository. And it has already caused problems with line endings on Windows. So maybe it's time to port it to another more portable language? (if we can call cmake a language...)

Extra information

  • µReact version: 0.1.0

Try to make observer for signal pack

It would be convenient to create an observer for a signal pack. It allows performing some actions if any of the listed signals are touched.

A similar can be done by creating a new signal that depends on this signal pack and with the type of tuple with all the types from the signal pack. But it's more verbose and the resulting tuple will be passed in observer without expansion.

Examples improvements

  • Need to make each example on separate exe. Don't need to group them, they are not autotests.
  • It would be a good idea to make some kind of approval tests for examples (comparing their output with their previous output).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.