Version: 4.1.1
Date: 2026-06-08
SPDX-License-Identifier: BSD-3-Clause
License File: See the LICENSE file in the project root
Copyright: © 2025-2026 Michael Gardner, A Bit of Help, Inc.
Status: Released
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
No unreleased changes yet.
- Publishability of the Alire community-index source: switch the
two
.gitmodulessubmodule URLs from SSH (git@github.com:...) back to HTTPS (https://github.com/...) so downstream consumers and Alire's deployment of the published source can clone the dev/tooling submodules without SSH credentials. Effectively reverses the URL portion off4863eb chore(submodules): switch submodule URLs from HTTPS to SSH. Library API and runtime behaviour are byte-identical to v4.1.0; this is a publishability patch only.
Try_To_Result- UseFunctional.Try.Map_To_ResultTry_To_Any_Result_With_Param- UseFunctional.Try.Map_To_Result_With_ParamTry_To_Functional_Result- UseFunctional.Try.Map_To_ResultTry_To_Result_With_Param- UseFunctional.Try.Map_To_Result_With_Param
Rationale: Declarative exception mappings (data) are clearer and more
maintainable than procedural Map_Exception functions (code). The Map
versions use a mapping array that is self-documenting and allows multiple
exception-to-error-kind discriminations without if/elsif chains.
Note: Option-based Try functions (Try_To_Functional_Option,
Try_To_Option_With_Param) are NOT deprecated. They serve valid use cases
for "probe" operations with sensible defaults where error details don't matter.
Functional.Try.To_Result- Reimplemented with inline exception handling instead of delegating to deprecatedTry_To_Functional_Result. This eliminates deprecation warnings when building the functional library itself.Functional.Try.To_Option- Reimplemented with inline exception handling instead of delegating toTry_To_Functional_Option(consistency).- Added "When to Use Option" documentation section to
functional-try.ads
- Suppress expected warnings in test suite:
test_try.adb: obsolescent warnings (testing deprecated functions still work)test_scoped.adb: "condition is always True" (intentional test pattern)
- Added
*__GNATPP-TEMPto.gitignore(GNAT Pretty Print temp files)
- Test Coverage: 269 unit tests (all passing)
- SPARK Status: 410 checks: 8 flow, 401 proved, 1 unproved (~98% proved) (--mode=prove --level=2)
Test Coverage: 269 unit + 0 integration + 0 examples = 269 total
- Removed exception-raising functions from Result and Option
Expectremoved from Result (was: extract value or raise Program_Error)Expect_Errorremoved from Result (was: extract error or raise Program_Error)Unwrap_Errorremoved from Result (was: extract error with precondition)Expectremoved from Option (was: extract value or raise Program_Error)
Rationale:
- Functional programming principle: Errors should be values, not exceptions. Exception-based control flow violates the core tenet of functional error handling.
- SPARK compatibility: SPARK formal verification prohibits exceptions. These functions were incompatible with SPARK_Mode => On despite the package annotation.
- Architectural consistency: The functional crate should model pure functional patterns without exception escape hatches.
Migration:
-- Old (3.0.0): Uses exception
Val := Int_Result.Expect (R, "Expected Ok");
-- New: Use precondition + Value (compile-time safety)
pragma Assert (Int_Result.Is_Ok (R));
Val := Int_Result.Value (R);
-- Or: Use Unwrap_Or for default fallback
Val := Int_Result.Unwrap_Or (R, Default_Value);New Exception Mapping Packages
Functional.Try.Map_To_Result- Declarative exception-to-Result mapping with configurable exception→error kind tables. Supports empty mappings (catch-all) or specific exception discrimination.Functional.Try.Map_To_Result_With_Param- Parameterized version for actions requiring input context (file paths, user IDs, etc.). Supports indefinite types.
New RAII Resource Management
Functional.Scoped.Guard_For- Unconditional RAII guard for automatic resource cleanup. Calls Release procedure when guard goes out of scope.Functional.Scoped.Conditional_Guard_For- Conditional RAII guard that checks Should_Release predicate before calling Release.
New Tests
- 11 tests for
Functional.Scopedcovering normal exit, exception paths, multiple guards, conditional release, and exception-safe Finalize behavior. - 35 tests for
Map_To_ResultandMap_To_Result_With_Paramcovering success paths, mapped exceptions, unmapped exceptions, and catch-all behavior.
- Hardened Finalize in Scoped -
Finalizeprocedures now catch all exceptions to prevent exception propagation during stack unwinding (which causes Program_Error or termination). - Keyword casing - Fixed
in Outtoin outin generic formal parameters. - Comment clarity - Fixed misleading "order doesn't matter" comment in Map_To_Result; now correctly states "first match wins if duplicates exist".
- Operation counts:
- Result: 33 operations (was 36, removed Expect/Expect_Error/Unwrap_Error)
- Option: 25 operations (was 26, removed Expect)
- Try: 7 operations (was 5, added Map_To_Result variants)
- Scoped: 2 generic packages (new)
- All 269 unit tests passing
- SPARK proved (Option, Result, Either, Version)
- SPARK proof coverage: 402 checks, 401 proved (99.7%), 270 subprograms analyzed
- Comprehensive instantiation tests (
test/spark/) exercise all generic operations - All helper functions proven overflow-safe
- Comprehensive instantiation tests (
- Scoped uses SPARK_Mode => Off (requires Ada.Finalization)
- Zero heap allocation maintained
- Boolean discriminants replace enumeration discriminants
- Option:
Kind→Has_Value(Boolean) - Result:
Kind→Is_Ok(Boolean),Err_Value→Error_Value - Either:
Kind→Is_Left(Boolean)
- Option:
- Result API renaming for clarity
Err→New_Error(constructor)Is_Err→Is_Error(predicate)Map_Err→Map_Error(transform)
- Try module generic formal renamed:
Err→New_Error
Documentation
docs/guides/cheatsheet.md- All types and operators on 1-2 pagesdocs/guides/user_guide.md- Design philosophy, SPARK, embedded, best practices
Result (30 operations, +13 new)
Zip_With- Combine two Results with a functionFlatten- Unwrap nested Result[Result[T,E],E] → Result[T,E]To_Option- Convert Ok(v) → Some(v), Error(_) → NoneContains- Check if Ok value equals given valueIs_Ok_And- Test if Ok and predicate holds (strict)Is_Error_And- Test if Error and predicate holds (strict)Is_Ok_Or- Test if Error or predicate holds on Ok (lenient)Is_Error_Or- Test if Ok or predicate holds on Error (lenient)Map_Or- Transform Ok value or return default (eager)Map_Or_Else- Transform Ok value or call default producer (lazy)Tap_Ok- Side effect on Ok onlyTap_Error- Side effect on Error only"or"operator forUnwrap_Or-R or Defaultsyntax"or"operator forFallback-A or Bsyntax"="operator forContains-R = Vsyntax
Option (25 operations, +14 new)
"and"operator - Returns second when both have values"xor"operator - Returns one when exactly one has valueZip_With- Combine two Options with a functionFlatten- Unwrap nested Option[Option[T]] → Option[T]Ok_Or- Convert Some(v) → Ok(v), None → Error(e) (eager)Ok_Or_Else- Convert Some(v) → Ok(v), None → Error(f()) (lazy)Contains- Check if Some value equals given valueIs_Some_And- Test if Some and predicate holds (strict)Is_None_Or- Test if None or predicate holds on Some (lenient)Map_Or- Transform Some value or return default (eager)Map_Or_Else- Transform Some value or call default producer (lazy)Tap- Side effect on Some value"or"operator forUnwrap_Or-O or Defaultsyntax"or"operator forOr_Else-A or Bsyntax"="operator forContains-O = Vsyntax
Either (20 operations, +12 new)
Map- Right-biased transform (convenience for common case)Swap- Exchange Left and Right valuesAnd_Then- Right-biased monadic bind for chainingContains- Check if Right value equals given valueIs_Left_And- Test if Left and predicate holds (strict)Is_Right_And- Test if Right and predicate holds (strict)Is_Left_Or- Test if Right or predicate holds on Left (lenient)Is_Right_Or- Test if Left or predicate holds on Right (lenient)Get_Or_Else- Get Right value or defaultMerge- Extract value when both types are the sameTo_Option- Convert Right(v) → Some(v), Left(_) → NoneTo_Result- Convert Right(v) → Ok(v), Left(e) → Error(e)"="operator forContains-E = Vsyntax
Discriminant access:
-- Old (2.x)
if R.Kind = K_Ok then ...
if O.Kind = K_Some then ...
-- New (3.0.0)
if R.Is_Ok then ...
if O.Has_Value then ...Result constructors/predicates:
-- Old (2.x)
Str_Result.Err (E);
if Str_Result.Is_Err (R) then ...
-- New (3.0.0)
Str_Result.New_Error (E);
if Str_Result.Is_Error (R) then ...Map_Error:
-- Old (2.x)
function Transform is new Str_Result.Map_Err (F => ...);
-- New (3.0.0)
function Transform is new Str_Result.Map_Error (F => ...);SPARK_Mode => Onfor Option, Result, Either (formally verifiable)SPARK_Mode => Offfor Try (exception boundary, by design)Preelaboratecategorization for Result, EitherPurecategorization for Version- Postconditions added to all transform operations for prover assistance
- Zero heap allocation, no controlled types, Ravenscar compatible
- All unit tests passing (Result, Option, Either, Try, Try_Option)
- Tested on POSIX (macOS, Linux) and Windows platforms
- stmt+decision coverage: 95%+
- Total operations: 80 (Result: 30, Option: 25, Either: 20, Try: 5)
- Expanded test coverage: Added tests for previously uncovered functions
Result.From_Error(boundary constructor - 3 tests)Result.And_Then_Into(type-changing monadic chain - 5 tests)Either.Map_Left(both Left and Right input paths)Either.Map_Right(both Left and Right input paths)Try.Try_To_Result_With_Param(success and exception paths)Try.Try_To_Option_With_Param(success and exception paths)- Coverage improved: 89% → 95% (exceeds 90% target)
- Documentation regeneration: Complete refresh of all documentation per documentation agent standards
- quick_start.md: Regenerated with all 44 operations (Result: 20, Option: 11, Either: 10, Try: 5)
- Added Map, Map_Err, Bimap examples for Result
- Added Filter example for Option
- Added Map_Left, Map_Right, Bimap, Fold examples for Either
- Added Try_To_Option and Try_To_Option_With_Param sections
- Added Tap/logging pattern to Common Patterns
- Formal docs (SRS, SDS, STG): Completely regenerated for functional library
- Previous content was from TZif project (incorrect)
- SDS now correctly describes nonhybrid utility library (not hexagonal architecture)
- Source file docstrings: Updated headers with operation counts and purpose descriptions
- config/README.md: Updated version to 2.3.0
- quick_start.md: Regenerated with all 44 operations (Result: 20, Option: 11, Either: 10, Try: 5)
- Project cleanup: Removed orphaned shared/ directory (release script generates to src/version/)
- GPR cleanup: Removed Documentation package reference (docs/api doesn't exist)
- Release script library detection: Added GPR-based project type detection
- Checks for
Library_NameorLibrary_Kindin GPR files - Correctly identifies nonhybrid utility libraries (like functional) as libraries
- Prepares for future distinction: hybrid_app, hybrid_lib, nonhybrid_lib
- Checks for
- Documentation terminology: Updated Try.ads comment to use "Boundary adapters" instead of "Infrastructure/Presentation" to avoid false positives in release validation
- All 101 unit tests passing (Result: 43, Option: 22, Either: 16, Try: 14, Try_Option: 6)
- stmt+decision coverage: 95%+
- All 20 Result operations now have tests (From_Error, And_Then_Into added)
- ROADMAP marker scanning: Release script now detects ROADMAP markers alongside TODO/FIXME/STUB
- ROADMAP markers indicate planned future work tracked in roadmap.md
- Helps identify deferred features during release preparation
- Library_Name casing: Changed from
"Functional"to"functional"in functional.gpr- Fixes GPRbuild elaboration object lookup (
p__functional_0.ovsp__Functional_0.o) - Follows GNAT convention: library name matches lowercase project filename
- Eliminates
ar: p__functional_0.o: not found in archivewarning in dependent projects
- Fixes GPRbuild elaboration object lookup (
- Alire deployment: Add
export-ignorefor submodules (scripts/python,test/python,docs/common) to prevent path collisions with dependencies during Alire source archive creation
- Preelaborate pragma for Option: Added
Preelaboratecategorization toFunctional.Option- Allows Option to be instantiated in preelaborable packages
- Enables use in domain/application layers with strict elaboration requirements
- Backwards compatible: only expands where Option can be used, no breaking changes
- All 83 Ada tests passing
- Zero breaking changes from 2.1.1
- Test Build Mode: Added "test" mode to functional.gpr for compatibility with downstream projects that use
-Xmode=test- Supports test-specific compiler flags (debug info, assertions, validity checks)
- Enables symbolic tracebacks in test mode
- Parameterized Try Functions: Enhanced exception handling with input context support
Try_To_Result_With_Param- Parameterized Result bridge for actions requiring input (e.g., console messages, file paths, user IDs)Try_To_Option_With_Param- Parameterized Option bridge for actions with input context- Support for indefinite types (String, unconstrained arrays) via
type Param (<>) is privategeneric formal parameter - Eliminates need for module-level mutable state and unsafe
Unchecked_Accesspatterns
- Backwards-Compatible Child Packages: Restored legacy API for existing code
Functional.Try.To_Result- Child package wrappingTry_To_Functional_Resultwith.RunAPIFunctional.Try.To_Option- Child package wrappingTry_To_Functional_Optionwith.RunAPI- Zero breaking changes - all existing test code continues to work unchanged
- Enhanced Documentation: Updated API documentation with parameterized Try usage patterns
- Added examples showing safe parameter passing without
Unchecked_Access - Documented indefinite type support (
type Param (<>) is private) - Updated architecture notes explaining exception boundary conversion
- Added examples showing safe parameter passing without
- Build Infrastructure: Modernized build system with standardized tooling
- Adopted Makefile from simple_hybrid with architecture validation (
check-arch) - Added cleanup utilities (
clean-clutter), Python testing (test-python), and tool installation targets - Renamed
tests/directory totest/for consistency with project standards - Updated test infrastructure to work with relocated
scripts/makefile/arch_guard.py - Professional colored test output with bordered success/failure banners
- Adopted Makefile from simple_hybrid with architecture validation (
- Type Safety: Generic formal parameters now support indefinite types (String, unconstrained arrays)
- Thread Safety: Parameterized approach eliminates module-level mutable state in client code
- All 83 Ada tests passing (Result: 35, Option: 22, Either: 12, Try: 14)
- All 35 Python tests passing (arch_guard validation suite)
- Zero unsafe code patterns required for using Try functions with parameters
- Fully backwards compatible with 2.0.0 API
- Try Module API Redesign: Complete refactoring of exception handling
- Try Module: Redesigned for maximum flexibility
- Renamed
Functional.Try.To_Result→Functional.Try.Try_To_Result - Renamed
Functional.Try.To_Option→Functional.Try.Try_To_Functional_Option - Added
Functional.Try.Try_To_Functional_Result(convenience for Functional.Result) Try_To_Resultnow works with any Result type (domain-specific, custom implementations)- Consolidated all Try functions into single
Functional.Trypackage - Removed child packages
Functional.Try.To_ResultandFunctional.Try.To_Option - Generic parameters allow bridging to any Result implementation with custom
Ok/Errconstructors
- Renamed
- Generic
Try_To_Resultsupports custom Result types with configurable constructors - Example code showing usage at infrastructure boundaries
- Comprehensive documentation for Try pattern in README
Old Code (1.0.0):
with Functional.Try.To_Result;
with Functional.Try.To_Option;
function Try_Read is new Functional.Try.To_Result (...);
function Try_Parse is new Functional.Try.To_Option (...);New Code (2.0.0):
with Functional.Try;
-- For custom domain Result types:
function Try_Read is new Functional.Try.Try_To_Result
(T => Integer_32, E => Error_Type,
Result_Type => Domain_Result.Result,
Ok => Domain_Result.Ok,
Err => Domain_Result.From_Error,
Map_Exception => From_Exception,
Action => Raw_Read);
-- For Functional.Result:
function Try_Parse is new Functional.Try.Try_To_Functional_Result
(T => String, E => Error,
Result_Pkg => Str_Result,
Map_Exception => From_Exception,
Action => Raw_Parse);
-- For Functional.Option:
function Try_Lookup is new Functional.Try.Try_To_Functional_Option
(T => Integer,
Option_Pkg => Int_Option,
Action => Raw_Lookup);Initial stable release of the Functional library for Ada 2022, providing type-safe functional programming abstractions including Result<T,E>, Option, Either<L,R>, and Try utilities (To_Result, To_Option) for exception handling.
-
Core Types:
Functional.Result<T,E>- Type-safe error handling with 17 operationsFunctional.Option<T>- Optional values with 11 operationsFunctional.Either<L,R>- Disjoint union type with 8 operationsFunctional.Try.To_Result- Convert exception-based code to ResultFunctional.Try.To_Option- Convert exception-based code to Option
-
Result Operations:
- Constructors:
Ok,Err - Predicates:
Is_Ok,Is_Err - Extractors:
Value,Error,Expect(with custom error messages) - Unwrapping:
Unwrap_Or,Unwrap_Or_With - Transformations:
Map,And_Then,Map_Err,Bimap - Recovery:
Fallback,Fallback_With,Recover,Recover_With - Validation:
Ensure,With_Context - Side effects:
Tap - Postconditions on
Unwrap_Orfor contract verification
- Constructors:
-
Option Operations:
- Constructors:
New_Some,None - Predicates:
Is_Some,Is_None - Extractors:
Value - Unwrapping:
Unwrap_Or,Unwrap_Or_With - Transformations:
Map,And_Then,Filter - Fallback:
Or_Else,Or_Else_With,Fallback(alias) - Postconditions on
Unwrap_Orfor contract verification
- Constructors:
-
Either Operations:
- Constructors:
Left,Right - Predicates:
Is_Left,Is_Right - Extractors:
Left_Value,Right_Value - Transformations:
Bimap(transform both sides),Fold(reduce to single value)
- Constructors:
-
Exception Handling:
Functional.Try.To_Result- Convert exception-raising code to Result<T,E>Functional.Try.To_Option- Convert exception-raising code to Option- Full exception information preservation in Try.To_Result
-
Testing:
- 83 comprehensive unit tests achieving 100% function coverage
- All packages tested with 90%+ code coverage target
- Test framework with aggregated reporting
-
Code Quality:
- Package-level generics (Ada 2022 best practice)
- Inline annotations for compiler optimization
- Preconditions and postconditions for contract programming
- Comprehensive API documentation with usage examples
- Line length convention: 120 characters for code, 80 characters for comments
- Comment separator lines standardized to exactly 80 characters