Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(218)

Unified Diff: docs/callback.md

Issue 2300983004: Move documentation of base::Callback from base/callback.h to docs/callback.md (Closed)
Patch Set: fix indentations. use codeblock for code snippets. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/callback.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: docs/callback.md
diff --git a/docs/callback.md b/docs/callback.md
new file mode 100644
index 0000000000000000000000000000000000000000..a380cf4b83ba4c417b79659fc11632a37e0a76d9
--- /dev/null
+++ b/docs/callback.md
@@ -0,0 +1,356 @@
+
+# Introduction
+
+The templated Callback class is a generalized function object. Together
+with the `Bind()` function in 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 (`base::Callback<void()>`)
+is called a `base::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.
+
+## 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.
+
+The reason to pass via a const-reference is to avoid unnecessary
+AddRef/Release pairs to the internal state.
+
+
+# Quick reference for basic stuff
+
+## BINDING A BARE FUNCTION
+
+```cpp
+int Return5() { return 5; }
+base::Callback<int()> func_cb = base::Bind(&Return5);
+LOG(INFO) << func_cb.Run(); // Prints 5.
+```
+
+## 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> {
+ 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);
+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.
+
+```cpp
+void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+ 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).
+
+```cpp
+void DoSomething(const base::Callback<double(double)>& callback) {
+ double myresult = callback.Run(3.14159);
+ myresult += callback.Run(2.71828);
+}
+```
+
+## 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) {}
+base::Callback<void(int, const std::string&)> cb = base::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 `Run()`ner 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) {}
+base::Callback<void()> cb = base::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:
+
+```cpp
+base::Closure cb = base::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");
+```
+
+## 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) {}
+base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+cb.Run("hello world");
+```
+
+When calling a function bound parameters are first, followed by unbound
+parameters.
+
+
+# Quick reference for advanced binding
+
+## BINDING A CLASS METHOD WITH WEAK POINTERS
+
+```cpp
+base::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 passing between threads!
+
+## BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
+
+```cpp
+base::Bind(&MyClass::Foo, base::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 CLASS
+
+```cpp
+MyClass* myclass = new MyClass;
+base::Bind(&MyClass::Foo, base::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.
+
+## 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; }
+base::Callback<void(int)> cb =
+ base::Bind(base::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).
+
+## 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));
+```
+
+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 scoped_ptr
+
+```cpp
+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));
+```
+
+Ownership of the parameter will be with the callback until the callback is
+run, and then 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.
+
+## PASSING PARAMETERS AS A scoped_refptr
+
+```cpp
+void TakesOneRef(scoped_refptr<Foo> arg) {}
+scoped_refptr<Foo> f(new Foo)
+base::Closure cb = base::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.
+
+## 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;
+base::Closure has_copy = base::Bind(&foo, n);
+base::Closure has_ref = base::Bind(&foo, base::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.
+
+## 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. Each `Callback` specialization has a templated
+constructor that takes an `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.
+
+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.
+
+The `Bind` functions do the above using type-inference, and template
+specializations.
+
+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 `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.
+
+`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
+void Foo(const char* ptr);
+void Bar(char* ptr);
+Bind(&Foo, "test");
+Bind(&Bar, "test"); // This fails because ptr is not const.
+```
+
+If you are thinking of forward declaring `Callback` in your own header file,
+please include "base/callback_forward.h" instead.
« no previous file with comments | « base/callback.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698