Update //docs/callback.md for OnceCallback and RepeatingCallback
Review-Url: https://codereview.chromium.org/2318113002
Cr-Commit-Position: refs/heads/master@{#423110}
diff --git a/docs/callback.md b/docs/callback.md
index af141b5..b891a0f 100644
--- a/docs/callback.md
+++ b/docs/callback.md
@@ -1,4 +1,4 @@
-# base::Callback<> and base::Bind()
+# Callback<> and Bind()
## Introduction
@@ -16,14 +16,66 @@
`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()`. This is a callback variant that is
+a move-only type and can be run only once. This moves out bound parameters from
+its internal storage to the bound function by default, so it's easier to use
+with movable types. This should be the preferred callback type: since the
+lifetime of the callback is clear, it's simpler to reason about when a callback
+that is passed between threads is destroyed.
+
+`RepeatingCallback<>` is created by `BindRepeating()`. This is a callback
+variant that is copyable that can be run multiple times. It uses internal
+ref-counting to make copies cheap. However, since ownership is shared, it is
+harder to reason about when the callback and the bound state are destroyed,
+especially when the callback is passed between threads.
+
+The legacy `Callback<>` is currently aliased to `RepeatingCallback<>`. In new
+code, prefer `OnceCallback<>` where possible, and use `RepeatingCallback<>`
+otherwise. Once the migration is complete, the type alias will be removed and
+`OnceCallback<>` will be renamed to `Callback<>` to emphasize that it should be
+preferred.
+
+`RepeatingCallback<>` is convertible to `OnceCallback<>` by the implicit
+conversion.
+
### Memory Management And Passing
-The Callback objects themselves should be passed by const-reference, and stored
-by copy. They internally store their state via a refcounted class and thus do
-not need to be deleted.
+Pass `Callback` objects by value if ownership is transferred; otherwise, pass it
+by const-reference.
-The reason to pass via a const-reference is to avoid unnecessary AddRef/Release
-pairs to the internal state.
+```cpp
+// |Foo| just refers to |cb| but doesn't store it nor consume it.
+bool Foo(const OnceCallback<void(int)>& cb) {
+ return cb.is_null();
+}
+
+// |Bar| takes the ownership of |cb| and stores |cb| into |g_cb|.
+OnceCallback<void(int)> g_cb;
+void Bar(OnceCallback<void(int)> cb) {
+ g_cb = std::move(cb);
+}
+
+// |Baz| takes the ownership of |cb| and consumes |cb| by Run().
+void Baz(OnceCallback<void(int)> cb) {
+ std::move(cb).Run(42);
+}
+
+// |Qux| takes the ownership of |cb| and transfers ownership to PostTask(),
+// which also takes the ownership of |cb|.
+void Qux(OnceCallback<void(int)> cb) {
+ PostTask(FROM_HERE, std::move(cb));
+}
+```
+
+When you pass a `Callback` object to a function parameter, use `std::move()` if
+you don't need to keep a reference to it, otherwise, pass the object directly.
+You may see a compile error when the function requires the exclusive ownership,
+and you didn't pass the callback by move.
## Quick reference for basic stuff
@@ -31,47 +83,67 @@
```cpp
int Return5() { return 5; }
-base::Callback<int()> func_cb = base::Bind(&Return5);
+OnceCallback<int()> func_cb = BindOnce(&Return5);
+LOG(INFO) << std::move(func_cb).Run(); // Prints 5.
+```
+
+```cpp
+int Return5() { return 5; }
+RepeatingCallback<int()> func_cb = BindRepeating(&Return5);
LOG(INFO) << func_cb.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 base::RefCountedThreadSafe<Ref> {
+class Ref : public RefCountedThreadSafe<Ref> {
public:
int Foo() { return 3; }
- void PrintBye() { LOG(INFO) << "bye."; }
};
scoped_refptr<Ref> ref = new Ref();
-base::Callback<void()> ref_cb = base::Bind(&Ref::Foo, 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.
+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.
+Callbacks can be run with their `Run` method, which has the same signature as
+the template argument to the callback. Note that `OnceCallback::Run` consumes
+the callback object and can only be invoked on a callback rvalue.
```cpp
-void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+void DoSomething(const Callback<void(int, std::string)>& callback) {
callback.Run(5, "hello");
}
+
+void DoSomethingOther(OnceCallback<void(int, std::string)> callback) {
+ std::move(callback).Run(5, "hello");
+}
```
-Callbacks can be run more than once (they don't get deleted or marked when
-run). However, this precludes using base::Passed (see below).
+RepeatingCallbacks can be run more than once (they don't get deleted or marked
+when run). However, this precludes using Passed (see below).
```cpp
-void DoSomething(const base::Callback<double(double)>& callback) {
+void DoSomething(const RepeatingCallback<double(double)>& callback) {
double myresult = callback.Run(3.14159);
myresult += callback.Run(2.71828);
}
@@ -84,7 +156,7 @@
```cpp
void MyFunc(int i, const std::string& str) {}
-base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
+Callback<void(int, const std::string&)> cb = Bind(&MyFunc);
cb.Run(23, "hello, world");
```
@@ -96,22 +168,22 @@
```cpp
void MyFunc(int i, const std::string& str) {}
-base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
+Callback<void()> cb = Bind(&MyFunc, 23, "hello world");
cb.Run();
```
-A callback with no unbound input parameters (`base::Callback<void()>`) is called
-a `base::Closure`. So we could have also written:
+A callback with no unbound input parameters (`Callback<void()>`) is called a
+`Closure`. So we could have also written:
```cpp
-base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
+Closure cb = Bind(&MyFunc, 23, "hello world");
```
When calling member functions, bound parameters just go after the object
pointer.
```cpp
-base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
+Closure cb = Bind(&MyClass::MyFunc, this, 23, "hello world");
```
### Partial Binding Of Parameters
@@ -121,19 +193,49 @@
```cpp
void MyFunc(int i, const std::string& str) {}
-base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+Callback<void(const std::string&)> cb = Bind(&MyFunc, 23);
cb.Run("hello world");
```
When calling a function bound parameters are first, followed by unbound
parameters.
+### Avoiding Copies with Callback Parameters
+
+A parameter of `Bind()` is moved into its internal storage if it is passed as a
+rvalue.
+
+```cpp
+std::vector<int> v = {1, 2, 3};
+// |v| is moved into the internal storage without copy.
+Bind(&Foo, std::move(v));
+```
+
+```cpp
+std::vector<int> v = {1, 2, 3};
+// The vector is moved into the internal storage without copy.
+Bind(&Foo, std::vector<int>({1, 2, 3}));
+```
+
+A bound object is moved out to the target function if you use `Passed()` for
+the parameter. If you use `BindOnce()`, the bound object is moved out even
+without `Passed()`.
+
+```cpp
+void Foo(std::unique_ptr<int>) {}
+std::unique_ptr<int> p(new int(42));
+
+// |p| is moved into the internal storage of Bind(), and moved out to |Foo|.
+BindOnce(&Foo, std::move(p));
+BindRepeating(&Foo, Passed(&p));
+```
+
## Quick reference for advanced binding
### Binding A Class Method With Weak Pointers
```cpp
-base::Bind(&MyClass::Foo, GetWeakPtr());
+Bind(&MyClass::Foo, GetWeakPtr());
```
The callback will not be run if the object has already been destroyed.
@@ -143,7 +245,7 @@
### Binding A Class Method With Manual Lifetime Management
```cpp
-base::Bind(&MyClass::Foo, base::Unretained(this));
+Bind(&MyClass::Foo, Unretained(this));
```
This disables all lifetime management on the object. You're responsible for
@@ -154,13 +256,20 @@
```cpp
MyClass* myclass = new MyClass;
-base::Bind(&MyClass::Foo, base::Owned(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.
+Smart pointers (e.g. `std::unique_ptr<>`) are also 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
@@ -168,22 +277,22 @@
```cpp
int DoSomething(int arg) { cout << arg << endl; }
-base::Callback<void(int)> cb =
- base::Bind(base::IgnoreResult(&DoSomething));
+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` (`base::Callback<void()>` and `base::Closure` are the same thing).
+`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);
-base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
+Closure foo_callback = Bind(&foo, Owned(pn));
```
The parameter will be deleted when the callback is destroyed, even if it's not
@@ -195,7 +304,7 @@
void TakesOwnership(std::unique_ptr<Foo> arg) {}
std::unique_ptr<Foo> f(new Foo);
// f becomes null during the following call.
-base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
+RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(&f));
```
Ownership of the parameter will be with the callback until the callback is run,
@@ -207,13 +316,22 @@
```cpp
void TakesOneRef(scoped_refptr<Foo> arg) {}
-scoped_refptr<Foo> f(new Foo)
-base::Closure cb = base::Bind(&TakesOneRef, f);
+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:
@@ -221,8 +339,8 @@
```cpp
void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
int n = 1;
-base::Closure has_copy = base::Bind(&foo, n);
-base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
+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"
@@ -230,8 +348,9 @@
```
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!
+**DANGER**: `ConstRef` stores a const reference instead, referencing the
+original parameter. This means that you must ensure the object outlives the
+callback!
## Implementation notes
@@ -240,27 +359,56 @@
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(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 evaluated to true and cancels the invocation if it's
+evaluated to false. 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.
+ 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. Each `Callback` specialization has a templated constructor
-that takes an `BindState<>*`. In the context of the constructor, the static
+bound parameters. The `Callback` constructor takes a `BindStateBase*`, which is
+upcasted from a `BindState<>`. In the context of the constructor, the static
type of this `BindState<>` pointer uniquely identifies the function it is
representing, all its bound parameters, and a `Run()` method that is capable of
invoking the target.
-`Callback`'s constructor takes the `BindState<>*` that has the full static type
-and erases the target function type as well as the types of the bound
-parameters. It does this by storing a pointer to the specific `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 `Run()`
-pointer.
+`Bind()` creates the `BindState<>` that has the full static type, and erases the
+target function type as well as the types of the bound parameters. It does this
+by storing a pointer to the specific `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 `Run()` pointer.
To `BindState<>` objects are created inside the `Bind()` functions.
These functions, along with a set of internal templates, are responsible for
@@ -273,8 +421,7 @@
parameters and that knows the correct refcounting semantics for the
target object if we are binding a method.
-The `Bind` functions do the above using type-inference, and template
-specializations.
+The `Bind` functions do the above using type-inference and variadic templates.
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
@@ -286,55 +433,13 @@
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 `MaybeRefcount()`
-functions respectively to modify the behavior of `Bind()`. The `Unwrap()` and
-`MaybeRefcount()` functions change behavior by doing partial specialization
-based on whether or not a parameter is a wrapper type.
+These types are passed to the `Unwrap()` functions to modify the behavior of
+`Bind()`. The `Unwrap()` functions change behavior by doing partial
+specialization based on whether or not a parameter is a wrapper type.
`ConstRef()` is similar to `tr1::cref`. `Unretained()` is specific to Chromium.
-### Why Not Tr1 Function/Bind?
-
-Direct use of `tr1::function` and `tr1::bind` was considered, but ultimately
-rejected because of the number of copy constructors invocations involved in the
-binding of arguments during construction, and the forwarding of arguments during
-invocation. These copies will no longer be an issue in C++0x because C++0x will
-support rvalue reference allowing for the compiler to avoid these copies.
-However, waiting for C++0x is not an option.
-
-Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
-`tr1::bind` call itself will invoke a non-trivial copy constructor three times
-for each bound parameter. Also, each when passing a `tr1::function`, each bound
-argument will be copied again.
-
-In addition to the copies taken at binding and invocation, copying a
-`tr1::function` causes a copy to be made of all the bound parameters and state.
-
-Furthermore, in Chromium, it is desirable for the `Callback` to take a reference
-on a target object when representing a class method call. This is not supported
-by tr1.
-
-Lastly, `tr1::function` and `tr1::bind` has a more general and flexible
-API. This includes things like argument reordering by use of
-`tr1::bind::placeholder`, support for non-const reference parameters, and some
-limited amount of subtyping of the `tr1::function` object (e.g.,
-`tr1::function<int(int)>` is convertible to `tr1::function<void(int)>`).
-
-These are not features that are required in Chromium. Some of them, such as
-allowing for reference parameters, and subtyping of functions, may actually
-become a source of errors. Removing support for these features actually allows
-for a simpler implementation, and a terser Currying API.
-
-### Why Not Google Callbacks?
-
-The Google callback system also does not support refcounting. Furthermore, its
-implementation has a number of strange edge cases with respect to type
-conversion of its arguments. In particular, the argument's constness must at
-times match exactly the function signature, or the type-inference might
-break. Given the above, writing a custom solution was easier.
-
### Missing Functionality
- - Invoking the return of `Bind`. `Bind(&foo).Run()` does not work;
- Binding arrays to functions that take a non-const pointer.
Example:
```cpp