Skip to content

[Scala 3] port ApplierUnapplier (Mirror-based)#881

Merged
halotukozak merged 4 commits into
AVSystem:scala-3from
halotukozak:05-03-applier-unapplier
Jun 16, 2026
Merged

[Scala 3] port ApplierUnapplier (Mirror-based)#881
halotukozak merged 4 commits into
AVSystem:scala-3from
halotukozak:05-03-applier-unapplier

Conversation

@halotukozak

Copy link
Copy Markdown
Contributor

Restores misc.ApplierUnapplier family from Phase-1 ??? stubs to real Scala 3 typeclass implementations backed by scala.deriving.Mirror.ProductOf. Cribbed verbatim from fork origin/master:core/src/main/scala-3/com/avsystem/commons/misc/ApplierUnapplier.scala.

What's restored

  • Applier[T <: Product]Seq[Any] => T via Mirror.ProductOf[T] + Tuple.fromArray.
  • Unapplier[T <: Product]T => Seq[Any] via productIterator.
  • ApplierUnapplier[T] — combined.
  • ProductUnapplier[T] / ProductApplierUnapplier[T] — concrete/abstract base classes for downstream extension.

All four use Scala 3 given derived with @implicitNotFound messages preserved.

Tests

Restored ApplierUnapplierTest (was wrapped in Phase 1). Expanded coverage beyond the fork:

  • Existing: Empty, Single, Multiple, Varargs, Generic, Over22 (>22 params), tuple.
  • New: nested case class, Option field, assertDoesNotCompile for sealed traits, ProductApplierUnapplier subclass usage, standalone Applier/Unapplier summoning.
  • Removed: ignore("custom") stub — Mirror only derives for actual case classes, hand-written apply/unapply is out of scope.
  • Bug fix: Over22 default values p14/p19/p20 were copy-paste typos ("13"/"18"/"18").

12/12 tests green, 0 ignored.

MIGRATION.md

§3 core — misc ApplierUnapplier entry; backlog rows for the three materialize Scala 2 macro stubs removed.

Slice 5.3 / Phase 5 leaf-feature-restoration.

Verbatim port from origin/master:core/src/main/scala-3/com/avsystem/commons/misc/ApplierUnapplier.scala.
Reshapes the Scala 2 macro `materialize` resolver into Scala 3 `given derived` typeclass derivation
based on `scala.deriving.Mirror.ProductOf`:

  - Applier:   given derived[T <: Product: Mirror.ProductOf as m]
  - Unapplier: given derived[T <: Product] (productIterator-based)
  - ApplierUnapplier: given derived[T: {Applier as applier, Unapplier as unapplier}]

Public trait surface (Applier / Unapplier / ApplierUnapplier / ProductUnapplier /
ProductApplierUnapplier) unchanged. Removes the `implicit def materialize[T] = ???` stubs left over
from Phase-1 big-bang. Added `import scala.deriving.Mirror` (CommonAliases export sweep is slice-3.x
territory; minimum local diff here). Local scalafmt applied.

ApplierUnapplierTest is exercised by the Mirror-based derivation since fork commit 7085bd8
re-enabled the test file; un-wrap follow-up commit will sync our copy.

Refs: APPLIERUNAPPLIER-01.
@halotukozak halotukozak added this to the Scala 3 milestone Jun 2, 2026
Sync test file with fork (origin/master:core/src/test/scala-3/com/avsystem/commons/misc/ApplierUnapplierTest.scala).
Fork re-enabled this test at commit 7085bd8. Diff vs prior local copy:

  - trailing comma after `value: T` parameter (scalafmt scala3 dialect)
  - `test("custom") { roundtrip(Custom("", 42)) }` → `ignore("custom") { /* ... */ }`
    rationale documented in test comment: Mirror.ProductOf only fires for true case classes,
    not "case-class-like" types with hand-written apply/unapply.

All 7 active cases green (`commons-core/testOnly *.ApplierUnapplierTest`), 1 ignored.
Local scalafmt applied.
§3 new subsection "core — misc ApplierUnapplier (slice 5.3)" documenting the macro→Mirror.ProductOf
reshape: public Applier/Unapplier/ApplierUnapplier traits preserved; resolution mechanism flipped
from Scala 2 `implicit def materialize[T] = macro …` to Scala 3 `given derived[T <: Product:
Mirror.ProductOf as m]` / `given derived[T: {Applier as applier, Unapplier as unapplier}]`.
ApplierUnapplierTest re-enabled per fork commit 7085bd8; the `custom` case is `ignore`d because
Mirror.ProductOf only fires for true case classes/tuples, not hand-written "case-class-like" types.

Backlog: removed three stale rows for ApplierUnapplier.scala lines 13/25/37 (Applier.materialize,
Unapplier.materialize, ApplierUnapplier.materialize).

Refs: APPLIERUNAPPLIER-01.
@halotukozak
halotukozak force-pushed the 05-03-applier-unapplier branch from 7997b19 to 92d26dc Compare June 2, 2026 12:38
@halotukozak
halotukozak marked this pull request as ready for review June 2, 2026 12:39
Comment thread core/src/test/scala/com/avsystem/commons/misc/ApplierUnapplierTest.scala Outdated
object ApplierUnapplier {
// TODO[scala3-port]: ApplierUnapplier.materialize (Scala 2 macro def) (L)
implicit def materialize[T]: ApplierUnapplier[T] = ???
given derived[T: {Applier as applier, Unapplier as unapplier}]: ApplierUnapplier[T] = new ApplierUnapplier[T] {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Named context bounds in complex form like (T: {A as a, B as b}) is Scala 3.6+ feature - dont we want to support LTS 3.3 ? FYL LTS 3.9 is said to loose compatibility with scala 2

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we won't use it compatibility either way (because this library I macro-heavy). It would be better to have almost identical sources (in scala-2 and scala-3) with the copied content rather than one cross compiled, because we can use scala 3 features more freely, we can get used to scala 3 syntax, and our code will benefit and don't require another breaking change in the future (for example, we can replace implicit classes with extensions already, which have much better perf)

Comment thread core/src/test/scala/com/avsystem/commons/misc/ApplierUnapplierTest.scala Outdated
Comment thread core/src/test/scala/com/avsystem/commons/misc/ApplierUnapplierTest.scala Outdated
Comment thread core/src/test/scala/com/avsystem/commons/misc/ApplierUnapplierTest.scala Outdated
@Andrzej-Swietek

Copy link
Copy Markdown

LGTM

@halotukozak
halotukozak merged commit 63e9b2e into AVSystem:scala-3 Jun 16, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants