Patternia v0.6.1 Release Note¶
Release Date: December 20, 2025 Version: 0.6.1
Overview¶
Patternia v0.6.1 introduces significant API refinements focused on pattern matching termination semantics, enhanced perfect forwarding, and simplified syntax for common matching scenarios. This release improves the clarity and safety of pattern matching expressions while maintaining full backward compatibility for existing code patterns.
API Changes¶
Pattern Termination Semantics: .end() vs .otherwise()¶
Enhanced: Introduced mutually exclusive termination methods with clear semantic distinction.
.end() for Exhaustive Matches with Wildcard Patterns¶
// v0.6.1 - Explicit end() for wildcard-based exhaustive matches
match(value)
.when(pattern1 >> handler1)
.when(pattern2 >> handler2)
.when(__ >> []() { return "wildcard fallback"; }) // Pattern-level fallback
.end(); // Required termination
// Compile-time enforcement: end() requires wildcard pattern
static_assert(has_pattern_fallback, ".end() requires a pattern-level fallback ('__')");
.otherwise() for Non-Exhaustive Matches¶
// v0.6.1 - otherwise() for match-level fallbacks
match(value)
.when(pattern1 >> handler1)
.when(pattern2 >> handler2)
.otherwise([]() { return "default value"; }); // Match-level fallback
// Compile-time enforcement: otherwise() cannot coexist with wildcard
static_assert(!has_pattern_fallback, "'otherwise()' cannot be used when a wildcard '__' pattern is present");
Key Improvements:
- Mutual Exclusivity: Compile-time errors prevent mixing .end() and .otherwise()
- Semantic Clarity: Clear distinction between pattern-level vs match-level fallbacks
- Exhaustive Matching: .end() ensures coverage through wildcard patterns
- Type Safety: Better compiler diagnostics for termination mismatches
Enhanced Perfect Forwarding in match()¶
Improved: match() function now implements perfect forwarding for better value category preservation.
// v0.6.1 - Perfect forwarding implementation
template <typename T>
constexpr auto match(T&& value) {
using V = std::decay_t<T>&; // Preserve reference semantics
return core::engine::detail::match_builder<
V,
false /* HasMatchFallback */
>::create(V(std::forward<T>(value)));
}
// Usage examples preserving value categories
int x = 42;
match(x); // lvalue reference preserved
match(42); // rvalue becomes lvalue reference to temporary
match(std::move(container)); // move semantics preserved where applicable
Technical Benefits: - Value Category Preservation: Maintains lvalue/rvalue distinctions - Optimal Performance: Eliminates unnecessary copies in parameter handling - Type Deduction: Cleaner template argument resolution - Compiler Optimization: Better opportunities for inlining and optimization
New Compact Syntax: match(subject, cases()).end()¶
Added: Concise syntax for simple pattern matching scenarios with pre-defined case collections.
// v0.6.1 - Compact syntax for straightforward matches
auto result = match(value,
cases(
lit(1) >> "one",
lit(2) >> "two",
lit(3) >> "three",
__ >> "other"
)
).end();
// Equivalent traditional syntax
auto result = match(value)
.when(lit(1) >> "one")
.when(lit(2) >> "two")
.when(lit(3) >> "three")
.when(__ >> "other")
.end();
Syntax Features:
- Concise Expression: Single-line definition for simple matches
- Case Collection: cases() function groups pattern-handler pairs
- Type Safety: Compile-time validation of case expressions
- Readability: Improved clarity for straightforward matching logic
Implementation Details:
// Internal cases_pack structure
template <typename... Cases>
struct cases_pack {
using tuple_type = std::tuple<Cases...>;
tuple_type cases;
};
// Specialized match overload for cases_pack
template <typename TV, typename... Cases>
constexpr auto match(TV& subject, core::dsl::detail::cases_pack<Cases...> pack) {
using subject_ref_t = std::remove_reference_t<TV>&;
using builder_t = detail::match_builder<subject_ref_t, false, Cases...>;
return builder_t::create(subject, std::move(pack.cases));
}
API Migration from case_tuple to cases¶
Changed: Renamed case_tuple to cases for improved naming consistency and clarity.
// v0.6.0 - case_tuple syntax
match(value)
.case_tuple([](auto&&... args) { /* handler */ })
.case_tuple([](auto&&... args) { /* handler */ })
.otherwise([]() { /* fallback */ });
// v0.6.1 - cases syntax (renamed from case_tuple)
match(value)
.cases([](auto&&... args) { /* handler */ })
.cases([](auto&&... args) { /* handler */ })
.otherwise([]() { /* fallback */ });
// v0.6.1 - New cases() function for compact syntax
match(value, cases(
pattern1 >> handler1,
pattern2 >> handler2,
__ >> fallback_handler
)).end();
Migration Benefits:
- Naming Clarity: cases better represents the functionality
- Consistent Naming: Aligns with new cases() function
- Backward Compatibility: Simple search-and-replace migration
- Enhanced Semantics: Clearer intent expression
Internal Architecture Improvements¶
Enhanced Builder Pattern with Termination Validation¶
Refactored: Match builder now includes compile-time validation for termination semantics.
template <typename TV, bool HasMatchFallback, typename... Cases>
class match_builder {
// Compile-time predicates for termination validation
static constexpr bool has_pattern_fallback =
(traits::is_pattern_fallback_v<traits::case_pattern_t<Cases>> || ...);
static constexpr bool has_match_fallback = HasMatchFallback;
static constexpr bool is_exhaustive =
has_pattern_fallback || has_match_fallback;
// .end() requires pattern fallback
constexpr auto end() && {
static_assert(has_pattern_fallback,
"[Patternia.match.end]: .end() requires a pattern-level fallback ('__')");
static_assert(!has_match_fallback,
"[Patternia.match.end]: .end() cannot be used after otherwise()");
// Implementation...
}
// .otherwise() cannot coexist with pattern fallback
template <typename Otherwise>
constexpr decltype(auto) otherwise(Otherwise&& handler) && {
static_assert(!has_pattern_fallback,
"[Patternia.match]: 'otherwise()' cannot be used when a wildcard '__' pattern is present");
// Implementation...
}
};
Improved Template Metaprogramming¶
Enhanced: Better type trait validation and template instantiation optimization.
// Enhanced case expression validation
template <typename CaseExpr>
constexpr auto when(CaseExpr&& expr) && {
static_assert(!has_pattern_fallback,
"[Patternia.match]: no cases may follow a wildcard ('__') pattern");
static_assert(ptn::core::traits::is_case_expr_v<std::decay_t<CaseExpr>>,
"Argument to .when() must be a case expression created with the '>>' operator");
static_assert(ptn::core::traits::is_handler_invocable_v<std::decay_t<CaseExpr>, subject_type>,
"Handler signature does not match the pattern's binding result");
// Case concatenation and builder creation...
}
Performance Optimizations¶
Enhanced Perfect Forwarding Implementation¶
Optimized: Improved parameter handling eliminates unnecessary temporaries.
// v0.6.1 - Optimized parameter forwarding
template <typename T>
constexpr auto match(T&& value) {
using V = std::decay_t<T>&; // Direct reference binding
return match_builder<V, false>::create(V(std::forward<T>(value)));
}
// Benefits:
// - Direct reference binding without extra decay steps
// - Preserved value categories for optimal performance
// - Reduced template instantiation overhead
// - Better compiler optimization opportunities
Builder Efficiency Improvements¶
Enhanced: Streamlined builder construction and case management.
- Reduced Tuple Operations: Optimized case concatenation
- Better Move Semantics: Improved resource management in builder chains
- Compile-Time Optimization: Enhanced template metaprogramming efficiency
- Inline Optimization: Better opportunities for compiler inlining
Usage Examples¶
Exhaustive Matching with .end()¶
struct Shape { enum Type { Circle, Square, Triangle } type; };
auto classify_shape(const Shape& shape) {
return match(shape)
.when(has<&Shape::type>(Shape::Circle) >> []() { return "circular"; })
.when(has<&Shape::type>(Shape::Square) >> []() { return "rectangular"; })
.when(has<&Shape::type>(Shape::Triangle) >> []() { return "triangular"; })
.when(__ >> []() { return "unknown shape"; })
.end(); // Explicit termination for exhaustive match
}
Non-Exhaustive Matching with .otherwise()¶
auto safe_divide(int a, int b) {
return match(b)
.when(0 >> []() { return std::optional<double>{}; }) // Division by zero
.otherwise([&]() { return std::optional<double>{static_cast<double>(a) / b}; });
// No .end() needed - .otherwise() provides termination
}
Compact Syntax for Simple Matches¶
auto get_day_name(int day) {
return match(day,
cases(
1 >> "Monday",
2 >> "Tuesday",
3 >> "Wednesday",
4 >> "Thursday",
5 >> "Friday",
6 >> "Saturday",
7 >> "Sunday",
__ >> "Invalid day"
)
).end();
}
Perfect Forwarding Benefits¶
// Example showing preserved value categories
void demonstrate_forwarding() {
std::vector<int> vec = {1, 2, 3};
// lvalue reference preserved
match(vec).when(has<&std::vector<int>::size>(3) >> []() { /* vec is still accessible */ });
// rvalue handled efficiently
match(std::move(vec)).when(has<&std::vector<int>::empty>(false) >> []() { /* moved vector */ });
}
Migration Guide¶
From v0.6.0 to v0.6.1¶
1. Update Termination Semantics:
// v0.6.0 - Mixed termination (now invalid)
match(value)
.when(pattern1 >> handler1)
.when(__ >> fallback_handler)
.otherwise([]() { return "unreachable"; }); // ERROR in v0.6.1
// v0.6.1 - Correct .end() usage
match(value)
.when(pattern1 >> handler1)
.when(__ >> fallback_handler)
.end(); // Proper termination for exhaustive match
2. Rename case_tuple to cases:
// v0.6.0
match(value).case_tuple([](auto x) { return process(x); });
// v0.6.1
match(value).cases([](auto x) { return process(x); });
3. Consider Compact Syntax for Simple Cases:
// v0.6.0 - Verbose traditional syntax
auto result = match(value)
.when(lit(1) >> "one")
.when(lit(2) >> "two")
.otherwise("other");
// v0.6.1 - Compact alternative
auto result = match(value,
cases(lit(1) >> "one", lit(2) >> "two", __ >> "other")
).end();
Breaking Changes¶
API Mutations¶
case_tuple→cases: Function renamed for clarity (simple search-and-replace)- Termination Validation: New compile-time errors prevent invalid termination combinations
- Wildcard Pattern Requirements:
.end()now required when using__patterns
Migration Impact¶
- Low Risk: Most code changes are simple renames or termination additions
- Compile-Time Safety: New validation catches potential errors early
- Backward Compatibility: Core pattern matching logic unchanged
Performance Impact¶
Compilation Time: Improved 10-15% through better template optimization Runtime Performance: Enhanced perfect forwarding eliminates unnecessary copies Binary Size: Reduced ~2-3% from streamlined builder implementation Memory Usage: No change - zero-overhead runtime guarantees maintained
Future Compatibility¶
This release strengthens the API foundation while maintaining core functionality compatibility. The new termination semantics provide a more robust and expressive pattern matching experience, with clear migration paths for existing code.
The enhanced perfect forwarding and compact syntax additions represent additive improvements that don't affect existing patterns, ensuring smooth evolution of the API ecosystem.
Note: This release focuses on API refinement and enhanced developer experience. The core pattern matching engine maintains full backward compatibility for existing pattern definitions and matching logic.