/attempt #517

Title Add structural schemas and .structural API (issue #517)

Summary Implements structural schemas and the new Schema.structural API to derive structural views for nominal types with a safe DynamicValue-backed fallback. This PR provides platform-aware derivation for Scala 3 and Scala 2.13, runtime adapters to expose structural views, tests, and docs.

What this PR does

  • Adds ToStructural typeclass derivation (Scala 3 and Scala 2 macro implementations).
  • Adds Schema.structural extension that returns a structural view of a derived schema.
  • Adds runtime adapters:
    • Scala 3: Selectable adapter from DynamicValue.
    • Scala 2: Dynamic adapter from DynamicValue.
  • Adds tests covering typed/untyped derivation, runtime conversion, and roundtrips.
  • Adds documentation and usage notes to docs/reference/ describing the .structural API and feature flags.
  • Adds .gitignore entry for generated trait sources.

Why

  • Enables easy, consistent structural views of schemas derived from nominal Scala types.
  • Provides a safe path: typed Scala 3 type-level derivation is attempted where possible; otherwise the macro falls back to a DynamicValue-backed schema to guarantee correctness and cross-build safety.

Local verification Commands used:

# Scala 3 JVM
sbt schemaJVM/test
# Scala 2.13 cross-build
sbt ++2.13.18 schemaJVM/test

Results:

  • Scala 3 JVM: 625 tests passed
  • Scala 2.13.18: 582 tests passed

Important notes / Limitations

  • The Scala 3 macro attempts typed Schema[GeneratedTrait] construction at the type-level, but constructing a fully typed Schema[GeneratedTrait] is not yet implemented in all cases; in those situations the macro falls back to a DynamicValue-backed schema and emits an informational message. This avoids unsafe casts and keeps the derivation correct across Scala versions.
  • Platform-specific sources were split into scala-3/ and scala-2/ directories to keep the cross-build green.
  • The feature to emit named trait sources is guarded behind feature flags and can generate temporary sources (ignored via .gitignore under /target/structural-generated/).

How to review (key places)

  • Macro & derivation:
    • schema/shared/src/main/scala-3/zio/blocks/schema/ToStructuralVersionSpecific.scala
    • schema/shared/src/main/scala-2/zio/blocks/schema/ToStructuralVersionSpecific.scala
  • Runtime adapters:
    • schema/shared/src/main/scala-3/zio/blocks/schema/StructuralRuntime.scala
    • schema/shared/src/main/scala-2/zio/blocks/schema/StructuralRuntime.scala
  • Tests:
    • schema/shared/src/test/... (Scala 3 tests)
    • schema/shared/src/test/scala-2/... (Scala 2 tests if present)
  • Docs:
    • docs/reference/structural usage and feature flag explanation.

Usage example

import zio.blocks.schema.Schema
val structSchema = Schema.derived[MyCaseClass].structural
// Use runtime adapter to access structural fields via Selectable (Scala 3) or Dynamic (Scala 2)

Feature flags (opt-in)

  • -Dzio.blocks.structural.enableNamedTrait=true
  • -Dzio.blocks.structural.emitNamedTraitSymbol=true
  • -Dzio.blocks.structural.emitToSource=true|false

Bounty claim instructions (per bounty rules)

  1. Start working: this PR includes /attempt #517 to indicate work begun.
  2. Submit work: include /claim #517 in this PR body to claim the bounty. (Included below.)
  3. Provide a short demo video: to be eligible for payout, please attach a short demo screencast showing:
    • Building the project (show sbt schemaJVM/test),
    • Running the structural tests,
    • A short example demonstrating Schema.derived[T].structural in the REPL or a tiny main. Attach the video file to this PR or provide a link to a hosted recording in the PR comments.
  4. Payouts: per the bounty, 100% of the reward is made 2–5 days post-reward after verification. Ensure you are eligible under the bounty rules.

/claim #517

Claim

Total prize pool $4,000
Total paid $0
Status Pending
Submitted December 29, 2025
Last updated December 29, 2025

Contributors

DI

Dipak Kumar

@dkrray772-gmail-com

100%

Sponsors

AN

anzal787

@anzal787

$2,000
ZI

ZIO

@ZIO

$2,000