Upgrade to Scala 3.7.4 and Modernization Audit#10
Merged
hakimjonas merged 19 commits intomainfrom Nov 22, 2025
Merged
Conversation
- Upgrade Scala version from 3.7.1 to 3.7.4 - Upgrade Scala Native from 0.5.8 to 0.5.9 - Add comprehensive modernization audit document - All tests passing (JVM + Native) The audit analyzes opportunities to leverage Scala 3.7.x improvements in inline metaprogramming, type class derivation, and macro capabilities. Key finding: Current architecture is already modern and well-designed. Includes phased modernization roadmap: - Phase 1 (v0.5.1): Quick wins - transparent inline, better errors - Phase 2 (v0.6.0): Type-level enhancements - Phase 3 (v0.7.0+): Future Scala 3.8+ features
…safety - Add `transparent inline` to MacroHelper.upcastTo for better type inference - Split deriveValidatorImpl into typed deriveSyncValidatorImpl/deriveAsyncValidatorImpl - Eliminate unnecessary .asExprOf casts by returning properly typed Expr - Add Position.ofMacroExpansion to all error messages for better IDE integration These changes follow the modernization roadmap from MODERNIZATION_AUDIT.md, improving code maintainability and developer experience with no functional changes.
Phase 1 - Zero-cast field access: - Case classes: Select.unique(a, "fieldName") - zero cast - Regular tuples: Select.unique(a, "_1") - zero cast - Named tuples: productElement with cast (matches stdlib pattern) - Remove MacroHelper.scala (no longer needed) Phase 2 - Type-level enhancements: - Inline Option detection during field processing (single pass) - Compile-time validator validation with comprehensive error messages - Type-level label extraction using pattern matching - Better error messages showing ALL missing validators at once Key changes: - Derivation.scala refactored with cleaner Scala 3 idioms - Added Scala 3.7.4 stdlib sources for reference (Tuple.scala, NamedTuple.scala)
- Replace "macros" terminology with "inline metaprogramming" - Update Scala version references to 3.7.4 - Update MODERNIZATION_AUDIT.md to reflect completed Phase 1 & 2 work - Remove MacroHelper.scala references (file was deleted) - Mark all implemented items as complete - Update roadmap and conclusions
- Remove IMPLEMENTATION_SUMMARY.md (internal dev log) - Remove MODERNIZATION_AUDIT.md (internal architecture audit) - Fix "macros" → "inline metaprogramming" in MIGRATION.md
README.md: - Remove emojis from headings and lists - Simplify language, reduce marketing tone - Consolidate redundant sections CONTRIBUTING.md: - Add basic contribution guidelines - Include development setup instructions - Document project structure
design.md: - Scala 2 vs Scala 3 typeclass derivation comparison - Architecture overview - Field access strategy explanation - Why inline metaprogramming examples.md: - Async validation with AsyncValidator - Validator composition (sequential and parallel) - Union and intersection type validation - Nested case classes - Collection validation
Named tuple field access requires asInstanceOf (matches Scala stdlib pattern). Null checks are defensive validation for potentially null field values.
Derivation no longer checks for null field values. This keeps the
core library simple and fast for idiomatic Scala 3 code.
For Java interop or Spark, users can define null-aware validators:
given Validator[String] with {
def validate(s: String) =
if (s == null) ValidationResult.invalid(...)
else ...
}
Changes:
- Remove null checks from sync and async field validation
- Remove unused isOption parameter from field generation
- Remove null-related tests (NullFieldTest, Team)
- Add documentation in TROUBLESHOOTING.md
Changes: - Remove 15 pass-through tests from ValidatorSpec (e.g., "Int validator should return Valid(x) for x") - these just verify the identity function - Update AsyncValidatorSpec Scaladoc to remove stale null references - Add ValidationConfigSpec with 5 tests covering: - Default unlimited collection sizes - Strict config 10,000 limit enforcement - Custom collection size limits - Fail-fast behavior (no element validation when size exceeded) - Make ValidationResultTestOps package-visible for test reuse - Minor scalafmt reformatting in Derivation.scala
Built-in validators for Int, String, Float, and Double now accept all values. Constraints are opt-in via ValidationHelpers. Why: The opinionated defaults (Int must be non-negative, String must be non-empty) limited Valar's use as a general-purpose foundation. Users validating temperatures, legacy data, or scientific values had to fight the library's defaults. Changes: - Validator[Int]: accepts all values (use nonNegativeInt for constraints) - Validator[String]: accepts all values (use nonEmpty for constraints) - Validator[Float]: accepts all values (use finiteFloat for constraints) - Validator[Double]: accepts all values (use finiteDouble for constraints) - AsyncValidator: updated to match sync validators - Tests: updated to verify pass-through behavior - Docs: updated Built-in Validators section, added migration guide
…traction Addresses reviewer feedback on DRY violation - collection validation logic was duplicated between Validator and AsyncValidator. New internal abstractions (private[valar]): - ValidationEffect[F[_]]: minimal monad-like trait for effect abstraction - SyncEffect: F[X] = X (identity, for sync validators) - FutureEffect: F = Future (for async validators) - ValidationLogic: shared collection/map validation, written once Changes: - Validator: collection validators now call ValidationLogic - AsyncValidator: collection validators now call ValidationLogic - Removed ~70 lines of duplicated traversal/folding logic Benefits: - Single source of truth for collection validation - Security logic (size checks) cannot drift between sync/async - Foundation ready for future F[_] effect support if needed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR upgrades Valar to Scala 3.7.4 and Scala Native 0.5.9, and includes a comprehensive modernization audit analyzing opportunities to leverage recent Scala 3 improvements.
Changes
Upgrades
3.7.1→3.7.40.5.8→0.5.9New Documentation
Test Results
Modernization Audit Highlights
Current State: Already Modern ✨
The audit confirms that Valar's metaprogramming architecture is already quite modern and well-designed:
Identified Opportunities
The opportunities are evolutionary, not revolutionary - focused on refinement rather than rewrites.
Phase 1: Quick Wins (v0.5.1) - ~8-10 hours
Transparent Inline for Better Type Inference
transparent inlinetoMacroHelper.upcastToEnhanced Error Messages with Source Positions
Split Macro Implementation
deriveValidatorImplinto separate sync/async macrosTotal Estimated Effort: 8-10 hours
Phase 2: Type-Level Enhancements (v0.6.0) - 1-2 months
Inline Match Types for Field Analysis
Compile-Time Validator Validation
Type-Level Field Path Construction
Phase 3: Future Exploration (v0.7.0+) - 6-12 months
Explicit Nulls Support (Scala 3.8+)
Capture Checking for Async Validation
Scala 3.7.x Improvements Leveraged
The audit analyzed Scala 3.7.x release improvements:
Inline Metaprogramming Analysis
Current inline usage is optimal:
Performance & Compatibility
Recommendations
Immediate Next Steps
Long-term Strategy
The upgrade validates that Valar's architecture is forward-compatible and robust. Focus should be on:
Breaking Changes
None. This is a fully backward-compatible upgrade.
Migration Guide
No changes required for library users. Simply update your Scala version to 3.7.4+ if desired.
Documentation
The MODERNIZATION_AUDIT.md document includes:
Review Focus Areas
Assessment: The codebase is in excellent shape. This upgrade confirms the architecture is modern, performant, and ready for future Scala improvements.