Skip to content

Remove the helpers in scala.deriving. #10405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

sjrd
Copy link
Member

@sjrd sjrd commented Nov 20, 2020

Draft PR for now to see what breaks in the community build.

@sjrd sjrd changed the title Review scala deriving Remove the helpers in scala.deriving. Nov 20, 2020
@sjrd sjrd added this to the 3.0.0-RC1 milestone Nov 20, 2020
@sjrd
Copy link
Member Author

sjrd commented Nov 20, 2020

The community build says that two projects are affected: scodec and upickle. This fits my earlier expectations that the members here are fairly specific to deserializers.


To follow up on our meeting:

There are two more-or-less separate things here:

  • ArrayProduct and EmptyProduct on the one hand, which IIUC were controversial but not too controversial.
  • productElement, which was pretty controversial.

ArrayProduct and EmptyProduct are exclusively used as arguments to Mirror.Product.fromProduct. If we want to bless ArrayProduct and EmptyProduct as a good way to create a Product to give to fromProduct, then I would suggest that we instead add a method fromArray in Mirror.Product. It can be implemented entirely in the library (it doesn't need code generation):

    /** The Mirror for a product type */
    trait Product extends Mirror {

      /** Create a new instance of type `T` with elements taken from product `p`. */
      def fromProduct(p: scala.Product): MirroredMonoType

      /** Create a new instance of type `T` with elements taken from the array `elems`. */
      def fromArray(elems: Array[AnyRef]): MirroredMonoType =
        fromProduct(new Product {
          def canEqual(that: Any): Boolean = true
          def productArity: Int = elems.length
          def productElement(n: Int): Any = elems(n)
        })
    }

There is then no need for overriding more stuff from Product, as fromProduct only calls productElement anyway.

That said, why are we blessing Arrays over other sequences? Why not accept all kinds of Seqs, for example? Blessing Arrays seems very ad hoc to me.


For productElement, only scodec uses it. upickle uses v.asInstanceOf[Product].productIterator instead.

@smarter
Copy link
Member

smarter commented Nov 20, 2020

So productElement hides two casts: one to Product and one to the result type, but is the first cast actually needed? Can't we statically know that the thing we're dealing with is a Product and not just an Any ? If we can't then how can we use productElement safely in the first place? If we can then there's already a productElement method on Product, so this method just hides one cast which doesn't seem worth it.

@sjrd
Copy link
Member Author

sjrd commented Nov 20, 2020

Yes, I also had that reasoning. I couldn't wrap my head around how either typeclass-derivation3 or scodec know that it is always a Product. It's used for example here:
https://github.com/lampepfl/dotty/blob/375de664073752eacfd631c9aee8a6cf98722422/tests/run/typeclass-derivation3.scala#L102
at which point it comes either from
https://github.com/lampepfl/dotty/blob/375de664073752eacfd631c9aee8a6cf98722422/tests/run/typeclass-derivation3.scala#L112
or
https://github.com/lampepfl/dotty/blob/375de664073752eacfd631c9aee8a6cf98722422/tests/run/typeclass-derivation3.scala#L162
In the second case it seems plausible that we know x: T to be a Product, although we cannot statically know it, because we got a ProductOf[T]. But even that is not clear when the ProductOf is a Mirror.SingletonProxy. But if having a ProductOf[T] is supposed to be a static guarantee that any x: T is a Product, we could define the following in Mirror.Product:

def asProduct(x: MirroredMonoType): Product = x.asInstanceOf[Product]

or even better, we could refine MirroredMonoType to have that as a static guarantee!

type MirroredMonoType <: Product

In the first case (in pickleCases), this does not work, because we don't even have a static proof that x is an alt to begin with. So I'm not sure what to do.

@smarter
Copy link
Member

smarter commented Nov 20, 2020

type MirroredMonoType <: Product

@milessabin ^ Do you think that makes sense?

@sjrd
Copy link
Member Author

sjrd commented Nov 21, 2020

Since it looks like we're going to release an M2, I opened #10436 which deprecates the helpers, so that we can more easily remove them in RC1. I have also improved the replacements in the tests, compared to this PR. IMO the replacements are better than using the helpers, at this point.

@sjrd sjrd force-pushed the review-scala-deriving branch from 64d9311 to 5c9aec4 Compare December 1, 2020 15:28
@anatoliykmetyuk anatoliykmetyuk modified the milestones: 3.0.0-M3, 3.0.0-RC1 Dec 14, 2020
@sjrd
Copy link
Member Author

sjrd commented Dec 17, 2020

Superseded by #10830

@sjrd sjrd closed this Dec 17, 2020
@sjrd sjrd deleted the review-scala-deriving branch December 17, 2020 20:39
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.

3 participants