Bartosz Milewski
Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor Monad Monoid
Sorting: compare function Find, copy_if: predicate function Accumulate: binary function for_each(v.begin(), v.end(), [](char c) { cout << c; }); transform(v.begin(), v.end(), w.begin(), [](int x) { return x * x; });
Currying, partial application: bind Combining algorithms v.erase(remove_if(v.begin(), v.end(), bind(logical_and (), bind(greater (), _1, -10), bind(less (), _1, 10))), v.end());
Channel for passing data (John Reppy, ML) Promise Future
Page 7 promise prms; Thread AThread B Promise Shared state Shared state
Shared state Shared state Page 8 promise prms; auto ftr = prms.get_future(); Thread AThread B Future Promise
Page 9 promise prms; auto ftr = prms.get_future(); thread th(&thFun, std::move(prms)); Thread AThread B Shared state Shared state Future Promise
Page 10 promise prms; auto ftr = prms.get_future(); thread th(&thFun, std::move(prms)); Thread AThread B Shared state Shared state Future Promise prms.set_value(Hello from future); Hello Thread B
Page 11 promise prms; auto ftr = prms.get_future(); thread th(&thFun, std::move(prms)); std::string str = ftr.get(); Thread AThread B Shared state Shared state Future Promise prms.set_value(Hello from future); Hello Thread B
Composability Orthogonality (Separation of concerns)
Problem: Apply a function to a future future ftr = async(…); … string s = ftr.get(); // blocks? … then continue to parse(s)
future ftr = async(…); string s = ftr.get(); // blocks? … then parse(s) template auto future::then(F&& func) -> future ; future fTree = ftr.then([](future fstr) { return parse(fstr.get()); // doesnt block }); Tree tree = fTree.get(); // blocks? future fTree = ftr.next(parse); Tree tree = fTree.get(); // blocks? Next combinator
next lifts parse to act on futures future fStr = … future fTree = fStr.next(parse); » transform lifts square to act on containers vector v = {1, 2, 3}; vector w; w.resize(v.size()); transform(v.begin(), v.end(), w.begin(), square);
Unconstrained parametric polymorphism (universally quantified types) For all types T: template class future; template class vector; template class unique_ptr; A mapping of types: T -> future
Type constructor Function lifting: then, transform, (Haskell: fmap) T -> future fuction -> function (future ));
Problem: Composing (chaining) async calls future async_open(string &); future async_read(HANDLE fh); In principle, this is the result: future > ffBuf = async_open("foo").next(&async_read);
Collapse two levels of future async_open("foo.cpp").next(&async_read).unwrap().n ext(&async_process).unwrap(); Combination of next and unwrap called bind (Haskell: >>=, bind combines join with fmap) In C++, next (then) can be overloaded to serve as bind
Usage: conditional asynchrony, recursion A future that is ready make_ready_future future fint = make_ready_future (42); int i = fint.get(); // doesnt block Analogously, for containers: vector v = {42};
Functor pattern Type constructor Function lifting (then, next, transform) Collapsing (unwrap, concat) Value lifting (make_ready_future)
Type constructor Value lifting: make_ready_future() bind: combination of.next(f).unwrap() [or an overload of next] Usage of the future monad pattern: Composing libraries of async functions
Its all in the wrist next (or bind) checks for exceptions and propagates them (without calling the continuation) At the end of the chain, recover from exception async_open("foo.cpp").next(&async_read).next(parse).r ecover(&on_error); Exception monad Implements short-circuiting Can be put on top of the future monad (monad transformers)
Problem: Need N futures to proceed. Create a barrier, get all values, proceed. when_all: takes futures, returns future of finished futures Client gets, iterates, gets each, and proceeds with values Functional approach Apply a regular function of n argument to n futures. Lifting of n-ary functions when_all_done(futures).next(fn) Together with make_ready_future: applicative functor
Problem: Wait for the first future to complete when_any: takes futures, returns a future of futures, at least one of them ready Client gets, iterates, checks is_ready, picks value. proceeds Functional approach The OR combinator (like addition?) Combines two futures into one Assoc.: (f1 OR f2) OR f3 = f1 OR (f2 OR f3) Neutral element: the never future never OR f = f = f OR never Defines a monoid
New patterns based on functional programming Functor Applicative Functor Monad Monoid Composability and orthogonality Result: Library of futures