| libfit |
| ====== |
| |
| FIT is a lean library of portable C++ abstractions for control flow and |
| memory management beyond what is offered by the C++ 17 standard library. |
| |
| FIT only depends on the C++ language and standard library, including the |
| `stdcompat` library to provide some C++ 17 library features. It offers |
| essential enhancements to the C++ standard library rather than attempting to |
| replace it or become a framework for writing applications. FIT can be thought |
| of as an "annex" that expresses a few ideas we wish the C++ standard library |
| might itself implement someday. |
| |
| FIT is lean. |
| |
| ## What Belongs in FIT |
| |
| Several Fuchsia SDK libraries, such as *libfidl*, depend on FIT and on the C++ |
| standard library. As these libraries are broadly used, we must take care in |
| deciding what features to include in FIT to avoid burdening developers with |
| unnecessary code or dependencies. |
| |
| In general, the goal is to identify specific abstractions that make sense to |
| generalize across the entire ecosystem of Fuchsia C++ applications. These will |
| necessarily be somewhat low-level but high impact. We don't want to add code to |
| FIT simply because we think it's cool. We need evidence that it is a common |
| idiom and that a broad audience of developers will significantly benefit from |
| its promotion. |
| |
| Here are a few criteria to consider: |
| |
| - Is the feature lightweight, general-purpose, and platform-independent? |
| - Is the feature not well served by other means, particularly by the C++ |
| standard library? |
| - Is the feature needed by a Fuchsia SDK library? |
| - Does the feature embody a beneficial idiom that clients of the Fuchsia SDK |
| commonly use? |
| - Has the feature been re-implemented many times already leading to code |
| fragmentation that we would like to eliminate? |
| |
| If in doubt, leave it out. See [Justifications] below. |
| |
| ## What Doesn't Belong in FIT |
| |
| FIT is not intended to become a catch-all class library. |
| |
| Specifically prohibited features: |
| |
| - Features that introduce dependencies on libraries other than the C and C++ |
| standard library. |
| - Features that only work on certain operating systems. |
| - Collection classes where the C++ 17 standard library already offers an |
| adequate (if not perfect) alternative. |
| - Classes that impose an implementation burden on clients such as event loops, |
| dispatchers, frameworks, and other glue code. |
| |
| ## Implementation Considerations |
| |
| FIT is not exception safe (but could be made to be in the future). |
| |
| ## Style Conventions |
| |
| FIT's API style follows C++ standard library conventions. |
| |
| In brief: |
| |
| - Class, method, field, and variable identifiers are `snake_case`. |
| - Template parameters are `CamelCase`. |
| - Preprocessor macros are `UPPER_SNAKE_CASE`. |
| - Whenever a FIT API mimics a C++ standard library API, it should have a |
| similar structure. For example, `fit::function` offers the same methods |
| as `std::function` except where necessary to diverge due to its move-only |
| semantics. |
| |
| Rule of thumb: Using FIT should feel like using the C++ standard library. |
| |
| ## Justifications |
| |
| These sections explain why certain features are in FIT. |
| |
| ### fit::function |
| |
| - *libfidl*'s API needs a callable function wrapper with move semantics but |
| C++ 14's `std::function` only supports copyable function objects which forces |
| FIDL to allocate callback state on the heap making programs less efficient |
| and harder to write. |
| - Lots of other C++ code uses callbacks extensively and would benefit from move |
| semantics for similar reasons. |
| - So we should create a move-only function wrapper to use everywhere. |
| |
| ### fit::defer |
| |
| - When writing asynchronous event-driven programs, it can become challenging |
| to ensure that resources remain in scope for the duration of an operation |
| in progress and are subsequently released. |
| - The C++ 14 standard library offers several classes with RAII semantics, such |
| as `std::unique_ptr`, which are helpful in these situations. Unfortunately the |
| C++ 14 standard library does not offer affordances for easily invoking a |
| function when a block or object goes out of scope short of implementing a |
| new class from scratch. |
| - We have observed several re-implementations of the same idea throughout the |
| system. |
| - So we should create a simple way to invoke a function on scope exit. |
| |
| ### fit::nullable |
| |
| - Case study: fit::defer has a need to store a closure that may be nullable. |
| We were able to replace its hand-rolled lifetime management code with |
| fit::nullable thereby vastly simplifying its implementation. |
| - Case study: fpromise::future has a need to track its own validity along with |
| a continuation that may or not be present. |
| - Case study: We have previously observed bugs where developers were |
| surprised when assigning a null closure to wrappers such as fit::function |
| fit::defer, or fpromise::future left these objects in a supposedly "valid" |
| but uninvocable state. These objects therefore take care to detect |
| null closures and enter an "invalid" state. Using fit::is_null and |
| fit::nullable makes it easier to eliminate this redundant state and |
| simplifies the API for clients of these wrappers. |
| - std::optional can be effective here but it doesn't directly handle nullity |
| so it takes more care to coalesce the null and "not present" states. |
| std::optional also increases the size of the object to carry an extra |
| bool and passing, whereas fit::nullable eliminates this overhead by |
| taking advantage of the underlying value's null state (if there is one). |
| - So we introduce fit::nullable to handle both cases systematically while |
| still hewing close to the semantics of std::optional. |