+++
title = "v2.2 major changes"
weight = 30
+++

Major changes in v2.2 over v2.1 are listed here.

1. A new trait `is_move_bitcopying<T>` is added, which opts types into a library-based emulation of
[P1029 *move = bitcopies*](https://wg21.link/P1029). [Experimental `std::error`](https://wg21.link/P1028) is opted in by default.
If this trait is true for your `T` or `E` type, Outcome will track moved-from status for your type,
and will only call your type's destructor if it was not moved from. If your compiler's optimiser is
sufficiently able to fold code, this improves codegen quality for Experimental Outcome very considerably,
approaching the same gains as P1029 types would have. Note that the empirical performance difference
will likely be nil, but the codegen does look much more elegant.

2. If for `basic_result<T, E>` both `T` and `E` are trivially copyable, union-based rather than
struct-based storage will be used. This significantly improves performance in synthetic benchmarks
which do nothing in deep call stacks of function calls except create and return `result<T, E>`, and
makes Outcome return competitive results to alternative error handling choices, improving comparative
optics. It is not expected that the performance difference will be detectable empirically in real
world code. It is expected that the build time impact of union storage won't be noticeable, as
union storage for trivially copyable types is much easier than for non-TC types.

    Note that storage remains struct-based if either `T` or `E` is neither trivially copyable nor for
    which trait `is_move_bitcopying<T>` is true. This is because union-based storage for complex
    types has significant build time impact, as anyone who has deployed `std::variant` or
    `std::expected` into globally visible public APIs will have noticed.

3. The compile time requirement for `E` types to have a default constructor is removed.

4. `OUTCOME_TRY(var, expr)` no longer always declares `var` as `auto &&var`, but simply uses it
as is. This allows `TRY` to initialise or assign. You can use the macro `OUTCOME21_TRY` if you
want the pre-Outcome v2.2 behaviour. You may find the regular expression `_TRY\(([^(]*?),(.*?)\);` =>
`_TRY(auto &&\1,\2);` of use to you when upgrading code.

5. `OUTCOME_TRY` now declares its internal uniquely named temporary variable which holds the result
of the expression as `auto unique = expr` instead of `auto &&unique = expr`. This will cause TRY of
`result<UncopyableAndImmovable>` and `outcome<UncopyableAndImmovable>` to fail to compile, whereas
previously they did compile. Another big change in semantic is that TRY now will 'consume' values
moved into it, whereas previously it did not/ The reason for this change was that the previous behaviour
produced undefined behaviour in various corner use cases, particulary in generic code. You can tell
TRY to use references instead of values for its uniquely named temporary [using a special
syntax]({{% relref "/tutorial/essential/result/try_ref" %}}).

6. `OUTCOME_TRY` now propagates the value from {{% api "spare_storage(const basic_result|basic_outcome *) noexcept" %}}
of the input Result/Outcome into any {{% api "failure_type<T>" %}} returned by TRY. Result/Outcome
now sets its spare storage value from any {{% api "success_type<T>" %}} or {{% api "failure_type<T>" %}}
from which it is constructed. This is a breaking change, as spare storage values were not propagated
beforehand. However this change means that any stack backtrace identifier captured by a failed
result construction hook is now fully propagated from failure point up through all TRY operations
to the code which handles the failure.

7. [The ADL discovered event hooks]({{% relref "/tutorial/advanced/hooks" %}}) have been replaced
with policy-specified event hooks instead. This is due to brittleness (where hooks would quietly
self-disable if somebody changed something), compiler bugs (a difference in compiler settings causes
the wrong hooks, or some but not all hooks, to get discovered), and end user difficulty in using
them at all. The policy-specified event hooks can be told to default to ADL discovered hooks for
backwards compatibility: set {{% api "OUTCOME_ENABLE_LEGACY_SUPPORT_FOR" %}} to less than `220` to
enable emulation.
