//base Newsletter, 2022Q3 Edition
What is this?
The Chromium //base code contains foundational building blocks for the project. It evolves over time to meet the project's changing needs. This periodic newsletter highlights some of the changes Chromium developers should be aware of.
New and shiny
base::expected<typename T, typename E>
A new vocabulary type based on the C++23 proposal that allows functions to return either an expected value of type T on success or an error value of type E on failure, e.g. instead of writing:
// Returns a base::Value::Dict on success, or absl::nullopt on failure. `error`
// will be populated with a diagnostic message on failure.
absl::optional<base::Value::Dict> ParseMyFormat(base::StringPiece input,
std::string& error);
Simply write this instead:
// Returns the parsed base::Value::Dict on success, or a string with a
// diagnostic message on failure.
base::expected<base::Value::Dict, std::string> ParseMyFormat(
base::StringPiece input);
Returning a success value is simple:
if (auto* dict = parsed_value.GetIfDict()) {
return std::move(*dict);
}
While returning an error value required using the base::unexpected
hint:
return base::unexpected(error_message);
Callers can use has_value()
to check for success, and then use value()
,
operator*
, or operator->
to access the success value. On error, callers can
use error()
instead to access the error value.
One notable divergence from the proposed C++23 library feature is the lack of a bool operator (explicit or otherwise).
- Prefer
base::expected<T, E>
overabsl::optional<T>
when returning auxiliary information for failures. - Helper types like
base::FileErrorOr<T>
should be migrated tobase::expected<T, base::FileError>
. - Mojo does not yet support this as a first-class primitive; see the open request.
New helpers in base/test/metrics/histogram_tester.h
Testing is an important part of Chromium. Even code that records metrics should have test coverage to help ensure the correctness of the metrics. To help support metrics testing, crrev.com/998514 and crrev.com/1002653 changed struct base::Bucket to accept enums, and added 4 new gMock matchers:
Now it is possible to write more concise test expectations when testing metrics.
base::ScopedBoostPriority
Chromium's architecture involves multiple processes and multiple threads. Giving threads the appropriate priority can greatly improve performance, but changing a thread's priority in a safe manner in cross-platform code can be tricky. To avoid subtle bugs, crrev.com/1013320 added base::ScopedBoostPriority to make it easier to boost a thread's priority in a controlled manner, without having to worry about the complications involved in restoring the original priority. Please consider using this scoper instead of calling base::PlatformThread::SetCurrentThreadType() directly.
Moreover, //base contains numerous scoper classes to make life easier for Chromium developers. Check out these examples.
Project updates
Standalone PartitionAlloc
The Chrome Memory Team is preparing to bring the benefits of PartitionAlloc to Chrome-external projects! Our first targets are PDFium (which uses an older copy of PA today), ARCVM, and d8. The goal here is to allow external clients to transparently use PartitionAlloc as their allocator of choice with a simple DEPS roll.
We've already completed most of the work of breaking dependencies on //base, which almost enables us to lift-and-shift the codebase as a single unit. More work is yet to come on doing the same for //build and other Chrome-isms. The team is currently working on assuming control of the shim in //base/allocator, which would allow us to provide the functional equivalent of PartitionAlloc-Everywhere for external clients.
base::Value API refactoring
The commonly used base::Value class has been refactoring its APIs for the last 6 years to better take advantage of modern C++ features. The original v1 proposal had some pain points that made adoption difficult. The v2 proposal addressed those problems and migration to the v2 APIs has been making lots of progress, with many deprecated APIs getting removed in the past year. Please consider helping with migration and take one of the bugs blocking the meta bug.
Issues with the v1 proposal that lead to the v2 proposal:
- The original plan was to entirely replace dictionaries with
base::flat_map<std::string, base::Value>
and lists withstd::vector<base::Value>
. - This turned out to be less practical than initially hoped:
base::DictionaryValue
andbase::ListValue
contained useful helpers that were all flattened intobase::Value
. Code that wants to use the helpers ends up losing type-safety and just using a genericbase::Value
everywhere. - In addition, directly exposing the underlying type makes it harder to make
future improvements. e.g. switching
base::Value
to useabsl::flat_hash_map
internally. - The v2 proposal implemented
base::Value::Dict
andbase::Value::List
to address the above issues.
Open issues with the refactoring:
- Migration can still be difficult to incrementally land.
base::Value::Dict
/base::Value::List
are not subclasses ofbase::Value
and do not really interoperate unless the caller is OK destructively passing the dict or list to function accepting abase::Value
.base::ValueView
is a read-only way for accepting values of all types but is not really intended for general usage (it's intentionally difficult to extract the exact subtype contained).base::DictAdapterForMigration
is a non-owning wrapper aroundbase::DictionaryValue
orbase::Value::Dict
. It exposes thebase::Value::Dict
API and allows callers of a function that takes this adapter type to be incrementally migrated.- TBD: Implement a corresponding adapter type for
base::Value::List
.
Reminders
How to use raw_ptr appropriately
The MiraclePtr project seeks to improve memory safety in Chromium. As part of this work, Chromium now uses the raw_ptr smart pointer class in many places. Being relatively new, here is a quick summary on how to use it appropriately:
raw_ptr<T>
use for class/struct fields in place of a raw C++ pointers is highly encouraged. Use whenever possible with a few caveats.raw_ptr<T>
should not be used for function parameters or return values.raw_ptr<T>
should be used in non-renderer code as class/struct members.- Renderer code uses the Oilpan garbage collector instead.
- A closely related smart pointer is raw_ref, for cases where a pointer cannot be null.
See base/memory/raw_ptr.md for more details.
Use base::BindLambdaForTesting() to simplify tests
When dealing with callbacks in tests, oftentimes it can be much easier to use base::BindLambdaForTesting() instead of base::BindRepeating()/BindOnce(). Example CL.
Bye bye
base::PostTask() and friends in base/task/post_task.h
base::PostTask()
was the original way of posting to the “thread pool” (then
named base::TaskScheduler
). It was then enhanced to allow base::TaskTraits
to specify BrowserThreads
as a destination. base::ThreadPool()
was later
added as a trait to force explicitly mentioning the destination. That was deemed
overly complicated and was moved to API-as-a-destination in
Task APIs v3.
Namely, base::ThreadPool::*
and content::Get(UI|IO)ThreadTaskRunner()
.
base/task/post_task.h
is gone as of
crrev.com/998343. However, on Android, the Java side
of PostTask()
still needs to go through this migration and is thus the only
(internal) caller remaining of the old traits-as-destination format which allows
//base to post to //content. //content Java browser thread APIs will need to be
added to fully finalize this API-as-a-destination migration and cleanup the
internal hooks for it.
base::CharTraits in base/strings/char_traits.h
This was a constexpr version of std::char_traits
from the <string>
header.
std::char_traits
became constexpr in C++17, so existing uses were migrated to
std::char_traits
and the //base version was removed in
crrev.com/993996.