the

most

valuable

values

by Juanpe Bolívar
https://sinusoid.al







Part I

Value semantics

value semantics

42
blue
"Juanpe Bolívar"
f(x) = x⁴

42
blue
"Juanpe Bolívar"
f(x) = x^2

am I a value?



Values are...
concrete material contingent temporary mutable
abstract immaterial necessary ethernal immutable
...I am a thing

Plato was wrong.

But his ideas are a useful metaphor
about how reasoning works.

things are real

values are imaginary

If things are not values,
how can we reason about things?

value of all existence
value of a given state
value of identity


We use language
to exchange values
e.g. Haskell

  let x = 42
      y = x + 2
      z = [ 1, 2, 3, 4 ]
      f = λ x -> x ^ 4
      w = map f z
            

{
    int foo = 42;
    int* p = &x;
    *p = x + 1;
    ...
}
          
“The limits of my language means the limits of my world.”
Ludwig Wittgenstein
object fetichism when all you can name is an object,
everything looks like an object

struct gesichtbuch {
    struct person {
         id_t id;
         std::string name;
         std::string email;
         std::string phone;
         int birth_year;
         std::vector<person*> friends;
         std::vector<person*> friends;
         std::vector<std::weak_ptr<person>> friends;
         std::vector<std::weak_ptr<person>> friends;
         std::vector<id_t> friends;
         std::unordered_set<id_t> friends;
    };
    std::vector<person> people;
    std::vector<std::unique_ptr<person>> people;
    std::vector<std::shared_ptr<person>> people;
    std::vector<std::shared_ptr<person>> people;
    std::vector<person> people;
    std::unordered_map<id_t, person> people;
    boost::multi_index<std::pair<id_t, id_t>, ...> friendships;
};

std::vector<int> push_back(std::vector<int> vec, int x)
{
    vec.push_back(x);
    return vec;
}
          

class foo {
    std::shared_ptr<impl> impl_;

public:
    foo modified(int arg) const& {;
        auto p = impl_->clone();
        p->mutate(arg);
        return foo{p};
    }
    foo&& modified(int arg) && {
        if (impl_->unique())           // unique() is not thread safe
            impl_->mutate(arg);        // according to std::shared_ptr.
        else                           // use your own implementation
            *this = modified();        // of reference counting
        return std::move(*this);
    }
};
          

class screen {
    screen_handle handle_;
    screen(const screen&) = delete;

public:
    screen&& draw(...) && {
        do_draw(handle_, ...);
    }

    auto draw(...) const {
        return [hdl=handle_] (context ctx) {
            do_draw(hdl, ...);
        };
    }
};
          

When to use value semantics?

OBJECTS macro design
VALUES micro design
VALUES macro design
OBJECTS micro design

Part II

A value based architecture
for interactive software

Example

An interactive counter


struct model
{
    int value = 0;
};

struct increment_action {};
struct decrement_action {};
struct reset_action { int value = 0; };

using action = std::variant<
    increment_action,
    decrement_action,
    reset_action>;
            

model update(model c, action action)
{
  return std::visit(lager::visitor{
    [&] (increment_action) {
        return model{ c.value + 1 };
    },
    [&] (decrement_action) {
        return model{ c.value - 1 };
    },
    [&] (reset_action a) {
        return model{ a.value };
    },
  }, action);
}
            

void draw(counter::model c) {
    std::cout << "current value: "
              << c.value << '\n';
}

std::optional<action> intent(char ev) {
    switch (ev) {
    case '+':
        return increment_action{};
    case '-':
        return decrement_action{};
    case '.':
        return reset_action{};
    default:
        return std::nullopt;
    }
}


            

int main()
{
    auto state = counter{0};
    auto event = char{};
    while (std::cin >> event) {
        if (auto act = intent(event)) {
            state = update(state, *act);
            draw(state);
        }
    }
}
            

Frameworks




void draw(model c) {  ... }
action intent(event_t ev) { ... }

int main() {
    auto debug = lager::http_debug_server{8080};
    auto serv  = boost::asio::io_service{};
    auto store = lager::make_store<action>(
        counter{0},
        update,
        draw,
        lager::boost_asio_event_loop{serv},
        lager::enable_debug(debug));
    auto term  = ncurses::terminal{serv};
    term.listen([&] (event_t ev) {
        store.dispatch(intent(ev));
    });
    serv.run();
}
            

template <typename Action, typename Model>
struct debugger
{
  struct goto_action { std::size_t cursor; };
  struct undo_action {};
  struct redo_action {};

  using action = std::variant<
      Action,
      goto_action,
      undo_action,
      redo_action
  >;
...
            

              ...
  struct model {
    Model init;
    std::size_t cursor = {};
    immer::vector<std::pair<Action, Model>>
        history = {};

    model(Model i) : init{i} {}
    operator const Model& () const {
        return cursor == 0
          ? init : history[cursor - 1].model;
    }
  };
};
            

model update(model m, action act, std::function<Model(Model, Action)> reducer)
{
    return std::visit(visitor{
            [&] (Action act) {
                ... reducer(m, act)
            },
            [&] (goto_action act) {
                ...
            },
            [&] (undo_action) {
                ...
            },
            [&] (redo_action) {
                ...
            },
    }, act);
}
        

int main() {
    auto debug = lager::http_debug_server{8080};
    auto meta  = lager::http_debug_server{8081};
    auto meta2 = lager::http_debug_server{8082};
    auto serv  = boost::asio::io_service{};
    auto store = lager::make_store<action>(
        counter{0},
        update,
        draw,
        lager::boost_asio_event_loop{serv},
        lager::enable_debug(serv),
        lager::comp(lager::enable_debug(debug),
                    lager::enable_debug(meta),
                    lager::enable_debug(meta2)));
    auto term  = ncurses::terminal{serv};
    term.listen([&] (event_t ev) {
        store.dispatch(intent(ev));
    });
    serv.run();
}
            

Closure

Further topics and
Conclusion

Effects


model update(model, action);
            

Effects


template <typename Action>
using effect = std::function<void(context<Action>)>;

pair<model, effect<action>> update(model, action);
            

Postmodern Immutable Data Structures

Juanpe Bolívar—CppCon 2017
youtu.be/sPhpelUfu8Q

No raw std::thread!

Live Tweet Analysis in C++

Kirk Shoop (RxCpp)—C++Now 2017
youtu.be/1-8gxwGN3S8
VALUES macro design
OBJECTS micro design
https://github.com/arximboldi/lager
https://github.com/arximboldi/immer
https://github.com/arximboldi/ewig
https://sinusoid.al
thanks.