Open
Description
I maintain an open source library at my company that has made it possible to cross-build a large, shapeless-heavy app for scala 2 and 3. Until recently I had just defined the minimal set of ops
needed for my codebase, but I've been working on fleshing out the remaining ones and I'm nearly done (with a few exceptions that don't make sense anymore). I'd be happy to port my changes to this repo and open a pull request if it would be received well!
These use scala.Tuple
directly instead of defining a separate HList
type. It would cover the ops
here:
- https://github.com/milessabin/shapeless/blob/main/core/shared/src/main/scala/shapeless/ops/hlists.scala
- https://github.com/milessabin/shapeless/blob/main/core/shared/src/main/scala/shapeless/ops/records.scala
as well as the syntax that uses those ops
here:
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
joroKr21 commentedon Aug 23, 2023
That's quite interesting. I think if we include them, they should be in a separate module. So far the strategy has been to add methods that work with polymorphic lambdas.
How do you manage to cross compile if you're using a different data structure between Scala 2 / Scala 3?
mrdziuban commentedon Aug 23, 2023
I have
Tuple
aliased toHList
,EmptyTuple
aliased toHNil
, and*:
aliased to::
-- https://github.com/mblink/typify/blob/more-shapeless-ops/tuple/shared/src/main/scala-2.13/typify/tuple/TuplePackageCompat.scala#L12-L16. So all downstream code looks like it's usingTuple
s but it's really using shapeless under the hood in scala 2.I should have clarified originally -- I don't intend to contribute everything to support cross-building, I'm happy to continue maintaining that compatibility layer for my own code. I was just thinking that having the
ops
type classes live in shapeless would be valuablejoroKr21 commentedon Aug 23, 2023
Wow, that's very clever. I think it could be valuable to even to include the aliases in a separate compat module.
mrdziuban commentedon Aug 23, 2023
I'm definitely open to including a compat module.
To add another layer of complexity to this, I've discovered that
Tuple#tail
is significantly less efficient thanHList#tail
. I asked in discord and the general reasoning is thatTuple
s are still encoded like they were in scala 2, and have efficient indexing, but inefficient head/tail decomposition. This is especially noticeable with the inductive implicit approach that most shapeless type classes use, where the recursive instance callstail
.As an example, I wrote a benchmark to test the inductive implicit encoding of
shapeless.ops.hlist.Remove
. Each method in the benchmark removes an element, 1 through 10, from anHList
/Tuple
of 10 elements . BothHList
andTuple
slow down as you get towards the end of the list, butTuple
performs much worse overall.HList
Tuple
All this said, do you think it would be better to redefine an
HList
type for scala 3 and provide conversions to/from nativeTuple
s?And regardless of the answer to that, should I go ahead and start porting the type classes into shapeless and open a PR when ready? If so, let me know if you have any thoughts on the name of the new module and/or the package structure that the code should follow.
joroKr21 commentedon Aug 24, 2023
In that case it might be better to try and finally finish cross-compiling Shapeless 2 to Scala 3: milessabin/shapeless#1200
Or start from scratch with a less ambitious version. I think
Generic
from mirrors would be enough.Katrix commentedon Aug 28, 2023
Generic from mirrors already exists in the Shapeless 2 for Scala 3 PR, so if something less ambitious is wanted, then one would just have to copy-paste that out. That's roughly what I did for a benchmark for my master thesis, and it worked just fine. IIRC the problem for a more general port was that the Scala 3 compiler didn't work well with some type programming stuff.