scalalandio / chimney

Scala library for boilerplate-free, type-safe data transformations

Home Page:https://chimney.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Be able to convert from NonEmptyList[T] to Seq[T]

codesurf42 opened this issue · comments

Describe the desired behavior
I would like to have an option to convert data structures with more functional data types like cats.data.NonEmptyList[T] to scala.collection.immutable.Seq[T] (could be a case where this structure is generated by protobuf), so I don't need to write such specific conversions for every data type.

Having generic conversion like

  implicit def nelInvalidARE[T]: Transformer[cats.data.NonEmptyList[T], Seq[T]] =
    from => from.map(_.transformInto[T]).toList

in scope doesn't help.

Use case example
"From" data type:
class Foo(data: NonEmptyList[String])

"To" data type:
class Bar(data: Seq[String])

How it relates to existing features
There is a module for cats-related extensions, but it doesn't support such conversions.

Additional context
I could help developing it and testing if I can get any more guidance with chimney.

Just to be clear: you are missing the ability to just import existing implicits, rather than write your own? Because providing the implicit works.

I'd say such thing is doable, but one would have to keep a few things in mind:

  • Chimney can derive conversions between Arrays/types that extends Iterable and types which have scala.collecion.compat.Factory, it would be nice if working with Cats types would allow using all such input/output types
  • Cats uses Applicative and Traverse to construct results, and there might be types in stdlib which have no typeclass - some custom approach might be needed (custom typeclass created from Traversable/Appliative and providing its own instances when Cats don't)
  • there are Total Transformers and Partial Transformers - the latter should keep traces of which index/key caused an error, so when writing an implicit for them one might need to use some zipWithIndex-like apprach
  • IME Maps and Map-like collections cannot reuse the same implicits, they need their own
  • implicit priorities will almost certainly be a thing to deal with
  • there is a risk of some platform-specific code (e.g. Scala collection compat doesn't help with .to(MapType) on 2.12 - you'll get Iterable[(Key, Value)])
  • similarly a matter of automatic-vs-semiautomatic derivation if elements of source and target collection types are different
  • all of that would have to be tested
  • similar idea was implemented in Java types' support, so this module can be used to steel some ideas

So all in all doable, but one has to be prepared for quite a bit of work

Thank you for quick response. Yes, looks like it works for simple types and that's what I have already tried.

Can you have a look while it doesn't work when T is a more complex type, like here: https://scastie.scala-lang.org/Q14e3vvvSuOLHvz227wyyQ

  • that's what I usually get in case of deeper ADTs.

Yes, such implicit would have to take another implicit: https://scastie.scala-lang.org/MateuszKubuszok/sxNjTJcdTti8yio8g0CRYA - I added a section about it in docs, that would be published in 0.8.1 (read it together with recommended automatic vs semiautomatic, since there us quite an important things there about the type of the implicit).

For me it works fine, so I don't feel like in need of this feature now. If I was to make chimney more user-friendly (and docs better searchable/gpt-ready), I would add the explicit example with smth like NonEmptyList[T] to the cookbook, especially there was the inner implicit auto-derived. I mean - not everyone will study all the docs before giving up on some library / such examples could attract more people to the user base.
In any case - thank you for your work and quick responses!

Well, I understand, but at the same time:

  • if I will have to add an example for every integration that someone might find useful then the docs would be 100 pages long
  • the search bar works great
  • and I rewritten docs from scratch like 3 weeks ago from this into this.

The release of a 0.8.x was a huge effort and I want to shift my attention to other things. I have some ideas what I also want to implement, but beyond that, if it's not a serious bug then I am leaving it at the hands of community.