Chromium Code Reviews| Index: docs/callback.md |
| diff --git a/docs/callback.md b/docs/callback.md |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8989d72893a1b8a6a186536fab7628cf2f7850e4 |
| --- /dev/null |
| +++ b/docs/callback.md |
| @@ -0,0 +1,433 @@ |
| +# base::Callback<> and base::Bind() |
|
dcheng
2016/08/31 06:20:53
Btw, can we move this in a separate CL? That way,
tzik
2016/08/31 08:14:10
Sounds good. Done.
|
| + |
| +## Introduction |
| + |
| +The templated `Callback<>` class is a generalized function object. Together with |
| +the `Bind()` function in base/bind.h, they provide a type-safe method for |
| +performing partial application of functions. |
| + |
| +Partial application (or "currying") is the process of binding a subset of a |
| +function's arguments to produce another function that takes fewer arguments. |
| +This can be used to pass around a unit of delayed execution, much like lexical |
| +closures are used in other languages. For example, it is used in Chromium code |
| +to schedule tasks on different MessageLoops. |
| + |
| +A callback with no unbound input parameters (`Callback<void()>`) is called a |
| +`Closure`. Note that this is NOT the same as what other languages refer to as a |
| +closure -- it does not retain a reference to its enclosing environment. |
| + |
| +### OnceCallback<> and RepeatingCallback<> |
| + |
| +`OnceCallback<>` and `RepeatingCallback<>` are next gen callback classes, |
| +which are under development. |
| + |
| +`OnceCallback<>` is created by `BindOnce()`, that is a restricted variant |
| +of `Callback<>` that is a move-only type and can run only once. It can handle |
| +movable types better as its bound parameter, and has clearer lifetime. Thus, |
| +thread hopping and result handning of an asynchronous operation are a good fit |
| +for it. |
| + |
| +`RepeatingCallback<>` is created by `BindRepeating()`, that is a loose variant. |
| +Its internal storage is ref-counted and `RepeatingCallback<>` itself is a |
| +copyable type. It can run more than once. So, it's suitable for event handlers |
| +that may happen more than once. It's discouraged to use this for a thread hop, |
| +since you cannot predict on which thread the callback object is destroyed. |
| + |
| +`RepeatingCallback<>` is convertible to `OnceCallback<>` by the implicit |
| +conversion. |
| + |
| +`Callback<>` is an alias of `RepeatingCallback<>` and `Bind()` is an alias of |
| +`BindRepeating()` for a historical reason. |
| + |
| +### Memory management and passing |
| + |
| +The `RepeatingCallback` objects should be passed by const-reference or by value, |
| +and stored by copy or by move. The `OnceCallback` object should be passed by |
| +value and stored by move. They internally store their state via a refcounted |
| +class and thus do not need to be deleted. |
| + |
| +## Quick reference for basic usage |
| + |
| +### Binding a bare function |
| + |
| +```cpp |
| +int Return5() { return 5; } |
| +Callback<int()> func_cb = Bind(&Return5); |
| +LOG(INFO) << func_cb.Run(); // Prints 5. |
| + |
| +OnceCallback<int()> func_cb2 = BindOnce(&Return5); |
| +LOG(INFO) << std::move(func_cb2).Run(); // Prints 5. |
| +``` |
| + |
| +### Binding a captureless lambda |
| + |
| +```cpp |
| +Callback<int()> lambda_cb = Bind([] { return 4; }); |
| +LOG(INFO) << lambda_cb.Run(); // Print 4. |
| + |
| +OnceCallback<int()> lambda_cb2 = BindOnce([] { return 3; }); |
| +LOG(INFO) << std::move(lambda_cb2).Run(); // Print 3. |
| + |
| +``` |
| + |
| +### Binding a class method |
| + |
| +The first argument to bind is the member function to call, the second is |
| +the object on which to call it. |
| + |
| +```cpp |
| +class Ref : public RefCountedThreadSafe<Ref> { |
| + public: |
| + int Foo() { return 3; } |
| +}; |
| + |
| +scoped_refptr<Ref> ref = new Ref(); |
| +Callback<void()> ref_cb = Bind(&Ref::Foo, ref); |
| +LOG(INFO) << ref_cb.Run(); // Prints out 3. |
| +``` |
| + |
| +By default the object must support RefCounted or you will get a compiler |
| +error. If you're passing between threads, be sure it's RefCountedThreadSafe! |
| +See "Advanced binding of member functions" below if you don't want to use |
| +reference counting. |
| + |
| +### Running a Callback |
| + |
| +Callbacks can be run with their "Run" method, which has the same signature as |
| +the template argument to the callback. |
| + |
| +`RepeatingCallback<>` can be run directly. |
| + |
| +```cpp |
| +void DoSomething(const RepeatingCallback<void(int, std::string)>& callback) { |
| + callback.Run(5, "hello"); |
| +} |
| +``` |
| + |
| +```cpp |
| +void DoSomething(const RepeatingCallback<double(double)>& callback) { |
| + double myresult = callback.Run(3.14159); |
| + myresult += callback.Run(2.71828); |
| +} |
| +``` |
| + |
| +`OnceCallback<>` can be run when it's a rvalue. Use `std::move` or |
| +`ResetAndReturn` to run it. |
| + |
| +```cpp |
| +void DoSomething(OnceCallback<void(int, double)> callback) { |
| + std::move(callback).Run(1, 0.1); |
| +} |
| +``` |
| + |
| +```cpp |
| +void DoSomething(OnceCallback<void()> callback) { |
| + ResetAndReturn(&callback).Run(); |
| +} |
| +``` |
| + |
| +`RepeatingCallback<>` can be run more than once (they don't get deleted or |
| +marked when run). However, this precludes using `Passed` (see below). |
| + |
| +### Passing unbound input parameters |
| + |
| +Unbound parameters are specified at the time a callback is Run(). They are |
| +specified in the Callback template type: |
| + |
| +```cpp |
| +void MyFunc(int i, const std::string& str) {} |
| +Callback<void(int, const std::string&)> cb = Bind(&MyFunc); |
| +cb.Run(23, "hello, world"); |
| +``` |
| + |
| +### Passing bound input parameters |
| + |
| +Bound parameters are specified when you create the callback as arguments to |
| +`Bind()`. They will be passed to the function and the runner of the callback |
| +doesn't see those values or even know that the function it's calling. |
| + |
| +```cpp |
| +void MyFunc(int i, const std::string& str) {} |
| +Callback<void()> cb = Bind(&MyFunc, 23, "hello world"); |
| +cb.Run(); |
| +``` |
| + |
| +A callback with no unbound input parameters (`Callback<void()>`, |
| +`OnceCallback<void()>` and `RepeatingCallback<void()>`) is called a |
| +`Closure`, `OnceClosure` and `RepeatingClosure`, respectively. |
| +So we could have also written: |
| + |
| +```cpp |
| +Closure cb = Bind(&MyFunc, 23, "hello world"); |
| +``` |
| + |
| +When calling member functions, bound parameters just go after the object |
| +pointer. |
| + |
| +```cpp |
| +Closure cb = Bind(&MyClass::MyFunc, this, 23, "hello world"); |
| +``` |
| + |
| +### PARTIAL BINDING OF PARAMETERS |
| + |
| +You can specify some parameters when you create the callback, and specify |
| +the rest when you execute the callback. |
| + |
| +```cpp |
| +void MyFunc(int i, const std::string& str) {} |
| +Callback<void(const std::string&)> cb = Bind(&MyFunc, 23); |
| +cb.Run("hello world"); |
| +``` |
| + |
| +## Quick reference for advanced binding |
| + |
| +### Binding a class method with weak pointers |
| + |
| +```cpp |
| +Bind(&MyClass::Foo, GetWeakPtr()); |
| +``` |
| + |
| +The callback will not be run if the object has already been destroyed. |
| + |
| +**DANGER**: weak pointers are not threadsafe, so don't use this when you pass it |
| +between threads! |
| + |
| +### Binding a class method with manual lifetime management |
| + |
| +```cpp |
| +Bind(&MyClass::Foo, Unretained(this)); |
| +``` |
| + |
| +This disables all lifetime management on the object. You're responsible for |
| +making sure the object is alive at the time of the call. You break it, you own |
| +it! |
| + |
| +### Binding a class method and having the callback own the instance |
| + |
| +```cpp |
| +MyClass* myclass = new MyClass; |
| +Bind(&MyClass::Foo, Owned(myclass)); |
| +``` |
| + |
| +The object will be deleted when the callback is destroyed, even if it's not run |
| +(like if you post a task during shutdown). Potentially useful for "fire and |
| +forget" cases. |
| + |
| +Also, smart pointers (e.g. `std::unique_ptr<>`) are supported as the receiver. |
| + |
| +```cpp |
| +std::unique_ptr<MyClass> myclass(new MyClass); |
| +Bind(&MyClass::Foo, std::move(myclass)); |
| +``` |
| + |
| +### Ignoring return values |
| + |
| +Sometimes you want to call a function that returns a value in a callback that |
| +doesn't expect a return value. |
| + |
| +```cpp |
| +int DoSomething(int arg) { cout << arg << endl; } |
| +Callback<void(int)> cb = |
| + Bind(IgnoreResult(&DoSomething)); |
| +``` |
| + |
| +## Quick reference for binding parameters to Bind() |
| + |
| +Bound parameters are specified as arguments to `Bind()` and are passed to the |
| +function. A callback with no parameters or no unbound parameters is called a |
| +`Closure` (`Callback<void()>` and `Closure` are the same thing). |
| + |
| +### Passing parameters owned by the callback |
| + |
| +```cpp |
| +void Foo(int* arg) { cout << *arg << endl; } |
| +int* pn = new int(1); |
| +Closure foo_callback = Bind(&foo, Owned(pn)); |
| +``` |
| + |
| +The parameter will be deleted when the callback is destroyed, even if it's |
| +not run (like if you post a task during shutdown). |
| + |
| +### Passing parameters as a unique_ptr |
| + |
| +```cpp |
| +void TakesOwnership(std::unique_ptr<Foo> arg) {} |
| +std::unique_ptr<Foo> f(new Foo); |
| +// f becomes null during the following call. |
| +RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(std::move(f))); |
| +``` |
| + |
| +Ownership of the parameter will be with the callback until it is run, when |
| +ownership is passed to the callback function. This means the callback can only |
| +be run once. If the callback is never run, it will delete the object when it's |
| +destroyed. |
| + |
| +```cpp |
| +void TakesOwnership(std::unique_ptr<Foo> arg) {} |
| +std::unique_ptr<Foo> f(new Foo); |
| +// f becomes null during the following call. |
| +OnceClosure cb = BindOnce(&TakesOwnership, std::move(f)); |
| +``` |
| + |
| +Parameters bound by `BindOnce()` are passed out even without `Passed`. |
| + |
| +### Passing movable objects |
| + |
| +```cpp |
| +void TakesMovableObject(std::vector<char> obj) {} |
| +std::vector<char> buf; |
| +Closure cb = Bind(&TakesMovableObject, Passed(&buf)); |
| +std::move(cb).Run(); |
| +``` |
| + |
| +When a bound argument is wrapped by `Passed()`, `Bind` moves the argument into |
| +its internal storage rather than copying it, and moves out it when the callback |
| +is run. |
| + |
| + |
| +```cpp |
| +void TakesMovableObject(std::vector<char> obj) {} |
| +std::vector<char> buf; |
| +OnceClosure cb = BindOnce(&TakesMovableObject, std::move(buf)); |
| +std::move(cb).Run(); |
| +``` |
| + |
| +`OnceCallback` moves out bound arguments even without `Passed`. |
| + |
| + |
| +```cpp |
| +void TakesMovableObject(std::vector<char> buf) {} |
| +std::vector<char> buf; |
| +Closure cb = Bind(&TakesMovableObject, std::move(buf)); |
| +cb.Run(); |
| +``` |
| + |
| +In contrast, when an object is bound with `std::move` into a `RepeatingCallback`, |
| +the bound object is copied when the callback is run. |
| + |
| +### Passing parameters as a scoped_refptr |
| + |
| +```cpp |
| +void TakesOneRef(scoped_refptr<Foo> arg) {} |
| +scoped_refptr<Foo> f(new Foo); |
| +Closure cb = Bind(&TakesOneRef, f); |
| +``` |
| + |
| +This should "just work." The closure will take a reference as long as it is |
| +alive, and another reference will be taken for the called function. |
| + |
| +```cpp |
| +void DontTakeRef(Foo* arg) {} |
| +scoped_refptr<Foo> f(new Foo); |
| +Closure cb = Bind(&DontTakeRef, RetainedRef(f)); |
| +``` |
| + |
| +`RetainedRef` holds a reference to the object and passes a raw pointer to |
| +the object when the Callback is run. |
| + |
| +### Passing parameters by reference |
| + |
| +Const references are *copied* unless ConstRef is used. Example: |
| + |
| +```cpp |
| +void foo(const int& arg) { printf("%d %p\n", arg, &arg); } |
| +int n = 1; |
| +Closure has_copy = Bind(&foo, n); |
| +Closure has_ref = Bind(&foo, ConstRef(n)); |
| +n = 2; |
| +foo(n); // Prints "2 0xaaaaaaaaaaaa" |
| +has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb" |
| +has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa" |
| +``` |
| + |
| +Normally parameters are copied in the closure. |
| + |
| +**DANGER**: `ConstRef` stores a const reference instead, referencing the |
| +original parameter. This means that you must ensure the object outlives the |
| +callback! |
| + |
| +## Implementation notes |
| + |
| +### Where is this design from: |
| + |
| +The design `Callback` and `Bind` is heavily influenced by C++'s |
| +tr1::function/tr1::bind, and by the "Google Callback" system used inside Google. |
| + |
| +### Customizing the behavior |
| + |
| +There are several injection points that controls `Bind` behavior from outside of |
| +its implementation. |
| + |
| +```cpp |
| +template <typename Receiver> |
| +struct IsWeakReceiver { |
| + static constexpr bool value = false; |
| +}; |
| + |
| +template <typename Obj> |
| +struct UnwrapTraits { |
| + template <typename T> |
| + T&& Unwrap(const T&& obj) { |
| + return std::forward<T>(obj); |
| + } |
| +}; |
| +``` |
| + |
| +If `IsWeakReceiver<Receiver>::value` is true on a receiver of a method, `Bind` |
| +checks if the receiver is null and cancels the invocation if it's null. |
| +You can specialize `IsWeakReceiver` to make an external smart pointer as a |
| +weak pointer. |
| + |
| +`UnwrapTraits<BoundObject>::Unwrap()` is called for each bound arguments right |
| +before `Callback` calls the target function. You can specialize this to define |
| +an argument wrapper such as Unretained, ConstRef, Owned, RetainedRef and Passed. |
| + |
| +### How the implementation works: |
| + |
| +There are three main components to the system: |
| + 1) The `Callback<>` classes. |
| + 2) The `Bind()` functions. |
| + 3) The arguments wrappers (e.g., `Unretained()` and `ConstRef()`). |
| + |
| +The Callback classes represent a generic function pointer. Internally, it stores |
| +a refcounted piece of state that represents the target function and all its |
| +bound parameters. `Callback` has a constructor that takes a `BindStateBase*` |
| +and `&Invoker::Run`. A `BindState<>` holds a function object to run, and also |
| +holds bound parameters. `BindStateBase` is the base class of of `BindState<>`, |
| +without type information of bound data. In the context of the constructor of |
| +`Callback`, `Invoker::Run` has the static type of `BindState<>` that identifies |
| +the function it is representing and all its bound parameters. |
| + |
| +`Bind()` creates the `BindState<>` that has the full static type, and erases the |
| +target function type as well as the type of bound parameters. It does this by |
| +taking a pointer to the specific `Invoker::Run()` function, and upcasting the |
| +state of `BindState<>` to a `BindStateBase`. This is safe as long as this |
| +`BindStateBase` pointer is only used with the stored `Invoker::Run()` pointer. |
| + |
| +To `BindState<>` objects are created inside the `Bind()` functions. |
| +These functions, along with a set of internal templates, are responsible for |
| + |
| + - Unwrapping the function signature into return type, and parameters |
| + - Determining the number of parameters that are bound |
| + - Creating the BindState storing the bound parameters |
| + - Performing compile-time asserts to avoid error-prone behavior |
| + - Returning an `Callback<>` with an arity matching the number of unbound |
| + parameters and that knows the correct refcounting semantics for the |
| + target object if we are binding a method. |
| + |
| +By default `Bind()` will store copies of all bound parameters, and attempt to |
| +refcount a target object if the function being bound is a class method. These |
| +copies are created even if the function takes parameters as const references. |
| +(Binding to non-const references is forbidden, see bind.h.) |
| + |
| +To change this behavior, we introduce a set of argument wrappers (e.g., |
| +`Unretained()`, and `ConstRef()`). These are simple container templates that |
| +are passed by value, and wrap a pointer to argument. See the file-level comment |
| +in base/bind_helpers.h for more info. |
| + |
| +These types are passed to the Unwrap() functions, and the IsWeakReceiver<> |
| +traits respectively to modify the behavior of Bind(). |
| + |
| +`ConstRef()` is similar to std::cref. `Unretained()` is specific to Chromium. |
| +`Owned()` and `RetainedRef()` let `BindState<>` have the exclusive or shared |
| +ownership and pass the bound item as a raw pointer to the target function. |