0

Fix docs/callback.md style

* Add document title
* Fix line wrapping

Review-Url: https://codereview.chromium.org/2314463002
Cr-Commit-Position: refs/heads/master@{#416597}
This commit is contained in:
tzik
2016-09-05 23:51:12 -07:00
committed by Commit bot
parent e7ffbf80d3
commit a431351621

@ -1,34 +1,33 @@
# base::Callback<> and base::Bind()
# Introduction ## Introduction
The templated Callback class is a generalized function object. Together The templated `Callback<>` class is a generalized function object. Together with
with the `Bind()` function in bind.h, they provide a type-safe method for the `Bind()` function in base/bind.h, they provide a type-safe method for
performing partial application of functions. performing partial application of functions.
Partial application (or "currying") is the process of binding a subset of Partial application (or "currying") is the process of binding a subset of a
a function's arguments to produce another function that takes fewer function's arguments to produce another function that takes fewer arguments.
arguments. This can be used to pass around a unit of delayed execution, This can be used to pass around a unit of delayed execution, much like lexical
much like lexical closures are used in other languages. For example, it closures are used in other languages. For example, it is used in Chromium code
is used in Chromium code to schedule tasks on different MessageLoops. to schedule tasks on different MessageLoops.
A callback with no unbound input parameters (`base::Callback<void()>`) A callback with no unbound input parameters (`Callback<void()>`) is called a
is called a `base::Closure`. Note that this is NOT the same as what other `Closure`. Note that this is NOT the same as what other languages refer to as a
languages refer to as a closure -- it does not retain a reference to its closure -- it does not retain a reference to its enclosing environment.
enclosing environment.
## MEMORY MANAGEMENT AND PASSING ### Memory Management And Passing
The Callback objects themselves should be passed by const-reference, and The Callback objects themselves should be passed by const-reference, and stored
stored by copy. They internally store their state via a refcounted class by copy. They internally store their state via a refcounted class and thus do
and thus do not need to be deleted. not need to be deleted.
The reason to pass via a const-reference is to avoid unnecessary The reason to pass via a const-reference is to avoid unnecessary AddRef/Release
AddRef/Release pairs to the internal state. pairs to the internal state.
## Quick reference for basic stuff
# Quick reference for basic stuff ### Binding A Bare Function
## BINDING A BARE FUNCTION
```cpp ```cpp
int Return5() { return 5; } int Return5() { return 5; }
@ -36,10 +35,10 @@ base::Callback<int()> func_cb = base::Bind(&Return5);
LOG(INFO) << func_cb.Run(); // Prints 5. LOG(INFO) << func_cb.Run(); // Prints 5.
``` ```
## BINDING A CLASS METHOD ### Binding A Class Method
The first argument to bind is the member function to call, the second is The first argument to bind is the member function to call, the second is the
the object on which to call it. object on which to call it.
```cpp ```cpp
class Ref : public base::RefCountedThreadSafe<Ref> { class Ref : public base::RefCountedThreadSafe<Ref> {
@ -57,7 +56,7 @@ error. If you're passing between threads, be sure it's
RefCountedThreadSafe! See "Advanced binding of member functions" below if RefCountedThreadSafe! See "Advanced binding of member functions" below if
you don't want to use reference counting. you don't want to use reference counting.
## RUNNING A CALLBACK ### Running A Callback
Callbacks can be run with their `Run` method, which has the same Callbacks can be run with their `Run` method, which has the same
signature as the template argument to the callback. signature as the template argument to the callback.
@ -78,7 +77,7 @@ void DoSomething(const base::Callback<double(double)>& callback) {
} }
``` ```
## PASSING UNBOUND INPUT PARAMETERS ### Passing Unbound Input Parameters
Unbound parameters are specified at the time a callback is `Run()`. They are Unbound parameters are specified at the time a callback is `Run()`. They are
specified in the `Callback` template type: specified in the `Callback` template type:
@ -89,12 +88,11 @@ base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
cb.Run(23, "hello, world"); cb.Run(23, "hello, world");
``` ```
## PASSING BOUND INPUT PARAMETERS ### Passing Bound Input Parameters
Bound parameters are specified when you create the callback as arguments Bound parameters are specified when you create the callback as arguments to
to `Bind()`. They will be passed to the function and the `Run()`ner of the `Bind()`. They will be passed to the function and the `Run()`ner of the callback
callback doesn't see those values or even know that the function it's doesn't see those values or even know that the function it's calling.
calling.
```cpp ```cpp
void MyFunc(int i, const std::string& str) {} void MyFunc(int i, const std::string& str) {}
@ -102,8 +100,8 @@ base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
cb.Run(); cb.Run();
``` ```
A callback with no unbound input parameters (`base::Callback<void()>`) A callback with no unbound input parameters (`base::Callback<void()>`) is called
is called a `base::Closure`. So we could have also written: a `base::Closure`. So we could have also written:
```cpp ```cpp
base::Closure cb = base::Bind(&MyFunc, 23, "hello world"); base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
@ -116,10 +114,10 @@ pointer.
base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world"); base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
``` ```
## PARTIAL BINDING OF PARAMETERS ### Partial Binding Of Parameters
You can specify some parameters when you create the callback, and specify You can specify some parameters when you create the callback, and specify the
the rest when you execute the callback. rest when you execute the callback.
```cpp ```cpp
void MyFunc(int i, const std::string& str) {} void MyFunc(int i, const std::string& str) {}
@ -130,44 +128,43 @@ cb.Run("hello world");
When calling a function bound parameters are first, followed by unbound When calling a function bound parameters are first, followed by unbound
parameters. parameters.
## Quick reference for advanced binding
# Quick reference for advanced binding ### Binding A Class Method With Weak Pointers
## BINDING A CLASS METHOD WITH WEAK POINTERS
```cpp ```cpp
base::Bind(&MyClass::Foo, GetWeakPtr()); base::Bind(&MyClass::Foo, GetWeakPtr());
`` ```
The callback will not be run if the object has already been destroyed. The callback will not be run if the object has already been destroyed.
DANGER: weak pointers are not threadsafe, so don't use this **DANGER**: weak pointers are not threadsafe, so don't use this when passing between
when passing between threads! threads!
## BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT ### Binding A Class Method With Manual Lifetime Management
```cpp ```cpp
base::Bind(&MyClass::Foo, base::Unretained(this)); base::Bind(&MyClass::Foo, base::Unretained(this));
``` ```
This disables all lifetime management on the object. You're responsible This disables all lifetime management on the object. You're responsible for
for making sure the object is alive at the time of the call. You break it, making sure the object is alive at the time of the call. You break it, you own
you own it! it!
## BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS ### Binding A Class Method And Having The Callback Own The Class
```cpp ```cpp
MyClass* myclass = new MyClass; MyClass* myclass = new MyClass;
base::Bind(&MyClass::Foo, base::Owned(myclass)); base::Bind(&MyClass::Foo, base::Owned(myclass));
``` ```
The object will be deleted when the callback is destroyed, even if it's The object will be deleted when the callback is destroyed, even if it's not run
not run (like if you post a task during shutdown). Potentially useful for (like if you post a task during shutdown). Potentially useful for "fire and
"fire and forget" cases. forget" cases.
## IGNORING RETURN VALUES ### Ignoring Return Values
Sometimes you want to call a function that returns a value in a callback Sometimes you want to call a function that returns a value in a callback that
that doesn't expect a return value. doesn't expect a return value.
```cpp ```cpp
int DoSomething(int arg) { cout << arg << endl; } int DoSomething(int arg) { cout << arg << endl; }
@ -175,13 +172,13 @@ base::Callback<void(int)> cb =
base::Bind(base::IgnoreResult(&DoSomething)); base::Bind(base::IgnoreResult(&DoSomething));
``` ```
# Quick reference for binding parameters to Bind() ## Quick reference for binding parameters to Bind()
Bound parameters are specified as arguments to `Bind()` and are passed to the 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 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` (`base::Callback<void()>` and `base::Closure` are the same thing).
## PASSING PARAMETERS OWNED BY THE CALLBACK ### Passing Parameters Owned By The Callback
```cpp ```cpp
void Foo(int* arg) { cout << *arg << endl; } void Foo(int* arg) { cout << *arg << endl; }
@ -189,10 +186,10 @@ int* pn = new int(1);
base::Closure foo_callback = base::Bind(&foo, base::Owned(pn)); base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
``` ```
The parameter will be deleted when the callback is destroyed, even if it's The parameter will be deleted when the callback is destroyed, even if it's not
not run (like if you post a task during shutdown). run (like if you post a task during shutdown).
## PASSING PARAMETERS AS A scoped_ptr ### Passing Parameters As A unique_ptr
```cpp ```cpp
void TakesOwnership(std::unique_ptr<Foo> arg) {} void TakesOwnership(std::unique_ptr<Foo> arg) {}
@ -201,12 +198,12 @@ std::unique_ptr<Foo> f(new Foo);
base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f)); base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
``` ```
Ownership of the parameter will be with the callback until the callback is Ownership of the parameter will be with the callback until the callback is run,
run, and then ownership is passed to the callback function. This means the and then ownership is passed to the callback function. This means the callback
callback can only be run once. If the callback is never run, it will delete can only be run once. If the callback is never run, it will delete the object
the object when it's destroyed. when it's destroyed.
## PASSING PARAMETERS AS A scoped_refptr ### Passing Parameters As A scoped_refptr
```cpp ```cpp
void TakesOneRef(scoped_refptr<Foo> arg) {} void TakesOneRef(scoped_refptr<Foo> arg) {}
@ -214,10 +211,10 @@ scoped_refptr<Foo> f(new Foo)
base::Closure cb = base::Bind(&TakesOneRef, f); base::Closure cb = base::Bind(&TakesOneRef, f);
``` ```
This should "just work." The closure will take a reference as long as it This should "just work." The closure will take a reference as long as it is
is alive, and another reference will be taken for the called function. alive, and another reference will be taken for the called function.
## PASSING PARAMETERS BY REFERENCE ### Passing Parameters By Reference
Const references are *copied* unless `ConstRef` is used. Example: Const references are *copied* unless `ConstRef` is used. Example:
@ -232,40 +229,38 @@ has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb"
has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa" has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa"
``` ```
Normally parameters are copied in the closure. DANGER: ConstRef stores a Normally parameters are copied in the closure.
const reference instead, referencing the original parameter. This means **DANGER**: ConstRef stores a const reference instead, referencing the original
that you must ensure the object outlives the callback! parameter. This means that you must ensure the object outlives the callback!
## Implementation notes
# Implementation notes ### Where Is This Design From:
## 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.
The design `Callback` and Bind is heavily influenced by C++'s ### How The Implementation Works:
`tr1::function`/`tr1::bind`, and by the "Google Callback" system used inside
Google.
## HOW THE IMPLEMENTATION WORKS:
There are three main components to the system: There are three main components to the system:
1) The Callback classes. 1) The Callback classes.
2) The `Bind()` functions. 2) The `Bind()` functions.
3) The arguments wrappers (e.g., `Unretained()` and `ConstRef()`). 3) The arguments wrappers (e.g., `Unretained()` and `ConstRef()`).
The Callback classes represent a generic function pointer. Internally, The Callback classes represent a generic function pointer. Internally, it stores
it stores a refcounted piece of state that represents the target function a refcounted piece of state that represents the target function and all its
and all its bound parameters. Each `Callback` specialization has a templated bound parameters. Each `Callback` specialization has a templated constructor
constructor that takes an `BindState<>*`. In the context of the constructor, that takes an `BindState<>*`. In the context of the constructor, the static
the static type of this `BindState<>` pointer uniquely identifies the type of this `BindState<>` pointer uniquely identifies the function it is
function it is representing, all its bound parameters, and a `Run()` method representing, all its bound parameters, and a `Run()` method that is capable of
that is capable of invoking the target. invoking the target.
`Callback`'s constructor takes the `BindState<>*` that has the full static type `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 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()` parameters. It does this by storing a pointer to the specific `Run()` function,
function, and upcasting the state of `BindState<>*` to a and upcasting the state of `BindState<>*` to a `BindStateBase*`. This is safe as
`BindStateBase*`. This is safe as long as this `BindStateBase` pointer long as this `BindStateBase` pointer is only used with the stored `Run()`
is only used with the stored `Run()` pointer. pointer.
To `BindState<>` objects are created inside the `Bind()` functions. To `BindState<>` objects are created inside the `Bind()` functions.
These functions, along with a set of internal templates, are responsible for These functions, along with a set of internal templates, are responsible for
@ -281,67 +276,64 @@ These functions, along with a set of internal templates, are responsible for
The `Bind` functions do the above using type-inference, and template The `Bind` functions do the above using type-inference, and template
specializations. specializations.
By default `Bind()` will store copies of all bound parameters, and attempt By default `Bind()` will store copies of all bound parameters, and attempt to
to refcount a target object if the function being bound is a class method. refcount a target object if the function being bound is a class method. These
These copies are created even if the function takes parameters as const copies are created even if the function takes parameters as const
references. (Binding to non-const references is forbidden, see bind.h.) references. (Binding to non-const references is forbidden, see bind.h.)
To change this behavior, we introduce a set of argument wrappers To change this behavior, we introduce a set of argument wrappers (e.g.,
(e.g., `Unretained()`, and `ConstRef()`). These are simple container templates `Unretained()`, and `ConstRef()`). These are simple container templates that
that are passed by value, and wrap a pointer to argument. See the are passed by value, and wrap a pointer to argument. See the file-level comment
file-level comment in base/bind_helpers.h for more info. in base/bind_helpers.h for more info.
These types are passed to the `Unwrap()` functions, and the `MaybeRefcount()` These types are passed to the `Unwrap()` functions, and the `MaybeRefcount()`
functions respectively to modify the behavior of `Bind()`. The `Unwrap()` functions respectively to modify the behavior of `Bind()`. The `Unwrap()` and
and `MaybeRefcount()` functions change behavior by doing partial `MaybeRefcount()` functions change behavior by doing partial specialization
specialization based on whether or not a parameter is a wrapper type. based on whether or not a parameter is a wrapper type.
`ConstRef()` is similar to `tr1::cref`. `Unretained()` is specific to Chromium. `ConstRef()` is similar to `tr1::cref`. `Unretained()` is specific to Chromium.
### Why Not Tr1 Function/Bind?
## WHY NOT TR1 FUNCTION/BIND?
Direct use of `tr1::function` and `tr1::bind` was considered, but ultimately Direct use of `tr1::function` and `tr1::bind` was considered, but ultimately
rejected because of the number of copy constructors invocations involved rejected because of the number of copy constructors invocations involved in the
in the binding of arguments during construction, and the forwarding of binding of arguments during construction, and the forwarding of arguments during
arguments during invocation. These copies will no longer be an issue in invocation. These copies will no longer be an issue in C++0x because C++0x will
C++0x because C++0x will support rvalue reference allowing for the compiler support rvalue reference allowing for the compiler to avoid these copies.
to avoid these copies. However, waiting for C++0x is not an option. However, waiting for C++0x is not an option.
Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the 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 `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 for each bound parameter. Also, each when passing a `tr1::function`, each bound
bound argument will be copied again. argument will be copied again.
In addition to the copies taken at binding and invocation, copying a 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 `tr1::function` causes a copy to be made of all the bound parameters and state.
state.
Furthermore, in Chromium, it is desirable for the `Callback` to take a Furthermore, in Chromium, it is desirable for the `Callback` to take a reference
reference on a target object when representing a class method call. This on a target object when representing a class method call. This is not supported
is not supported by tr1. by tr1.
Lastly, `tr1::function` and `tr1::bind` has a more general and flexible API. Lastly, `tr1::function` and `tr1::bind` has a more general and flexible
This includes things like argument reordering by use of API. This includes things like argument reordering by use of
`tr1::bind::placeholder`, support for non-const reference parameters, and some `tr1::bind::placeholder`, support for non-const reference parameters, and some
limited amount of subtyping of the `tr1::function` object (e.g., limited amount of subtyping of the `tr1::function` object (e.g.,
`tr1::function<int(int)>` is convertible to `tr1::function<void(int)>`). `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 These are not features that are required in Chromium. Some of them, such as
allowing for reference parameters, and subtyping of functions, may actually allowing for reference parameters, and subtyping of functions, may actually
become a source of errors. Removing support for these features actually become a source of errors. Removing support for these features actually allows
allows for a simpler implementation, and a terser Currying API. for a simpler implementation, and a terser Currying API.
## WHY NOT GOOGLE CALLBACKS? ### Why Not Google Callbacks?
The Google callback system also does not support refcounting. Furthermore, The Google callback system also does not support refcounting. Furthermore, its
its implementation has a number of strange edge cases with respect to type implementation has a number of strange edge cases with respect to type
conversion of its arguments. In particular, the argument's constness must conversion of its arguments. In particular, the argument's constness must at
at times match exactly the function signature, or the type-inference might times match exactly the function signature, or the type-inference might
break. Given the above, writing a custom solution was easier. break. Given the above, writing a custom solution was easier.
### Missing Functionality
## MISSING FUNCTIONALITY
- Invoking the return of `Bind`. `Bind(&foo).Run()` does not work; - Invoking the return of `Bind`. `Bind(&foo).Run()` does not work;
- Binding arrays to functions that take a non-const pointer. - Binding arrays to functions that take a non-const pointer.
Example: Example: