avro4s icon indicating copy to clipboard operation
avro4s copied to clipboard

Remove auto-derivation enabled by default

Open atnoya opened this issue 3 years ago • 6 comments

Hi there,

This might be a bit controversial, but auto-derivation is bringing quite a few non-small problems to us, from increased compilation times, to inadvertently, codifying case class that weren't expected to be there.

We are defining the Codecs/SchemaFor explicitly, and that helps, but it's inconvenient to not have the help of the compiler to tell you which one is missing because the missing ones are auto generated.

I would rather have explicit imports for the required behaviour, like circe or zio-json:

  • import com.sksamuel.avro4s.derivation.auto._
  • import com.sksamuel.avro4s.derivation.semi._

I am aware if accepted this is a breaking change, but If accepted, I would be willing to put forward a PR.

atnoya avatar May 27 '21 12:05 atnoya

I think this is a good idea but the focus should go into 5.0 which will be for Scala 3. 4.x is really just in bug fix mode as I focus on writing a scala 3 version.

sksamuel avatar Jun 02 '21 00:06 sksamuel

Given the nature of the change being a breaking change, I think it is fair :) Thanks! I haven't become familiar with scala 3 yet, but If I can help let me know!

atnoya avatar Jun 02 '21 08:06 atnoya

So, just to make sure I'm on the same page. semi auto derivation is where you go

val encoder = Encoder[Foo].

And auto is when you just request Encoder[F] and get one for everyone.

sksamuel avatar Jun 06 '21 21:06 sksamuel

Yeah, pretty much, I would say:

Semiauto is where you define your typeclass instances in the companion object (usually) by calling the gen macro.

And at the calling site, e.g.:

def useMyEncoder[A: Encoder]: Unit = ???

//If encoder defined in the companion object use that. 
//If you wish to use auto derivation, just include:
//import com.sksamuel.avro4s.derivation.auto._
useMyEncoder[A]

//If you don't define an instance in the companion object of A (or include a relevant import where the Encoder is defined), or add the `auto` import, compilation will not be able to find a suitable instance, and hence, failing.

atnoya avatar Jun 08 '21 09:06 atnoya

Yea, this one bit me too. I spent days trying to figure out why the FieldMapper wasn't working. It turns out that the macro looks at the local scope at every point where the Decoder is requested. This means that you cannot define the correct FieldMapper for the model in the companion object where the schema is generated (as you do for most type-class based codecs). This is especially a problem when some models use snake_case and others do not as you cannot mix the two in a generic situation as you cannot know which type needs which FieldMapper. The fact that auto-derivation is the default and the field mapper is assumed based on local scope effectively makes the FieldMapper unusable for us.

jeffmay avatar Oct 07 '21 19:10 jeffmay