Skip to content
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

HList based tupler #60

Open
Fristi opened this issue Oct 30, 2017 · 7 comments
Open

HList based tupler #60

Fristi opened this issue Oct 30, 2017 · 7 comments
Labels
scala 3 Requires features from Scala 3

Comments

@Fristi
Copy link
Contributor

Fristi commented Oct 30, 2017

I've used shapeless' hlist's to build up product types as seen here: https://github.com/Fristi/endpoints-proto/blob/master/algebra/src/main/scala/itinere/Tupler.scala.

Advantages:

  • No 22 tuple limit
  • We can use the Generic machinery of shapeless to map to case classes
@Krever
Copy link
Collaborator

Krever commented Nov 11, 2017

@julienrf Do you think it pays the cost of introducing first dependency to core algebra?

Idea looks interesting and for sure worth investigating but I'm not sure if its beneficial enough. Mapping to case classes may be a really nice feature though.

I had a different idea at some point, to remove tupler at all. User then has to deal with Units but it would simplify the api a lot.

@julienrf
Copy link
Member

In the beginning I considered using shapeless’ HList instead of tuples but I thought it was not worth introducing a dependency on shapeless just to get an HList definition (we use no operations on HList and no feature of shapeless). But in practice I often have shapeless in my classpath anyway because I do typeclass derivation in some places. So, why not use shapeless’ HList instead of tuples, if that also makes life easier for case classes mapping.

Note that it should still be possible to map to case classes without introducing shapeless in the core, but at the (cheap) cost of an additional implicit parameter.

@julienrf
Copy link
Member

One advantage of using tuples is that the syntax to “call” an endpoint is very similar to calling a method with several parameters (excepted that it’s a single tuple parameter):

val foo: Endpoint[(Int, String), Int] = …
foo((42, "bar"))

On the other hand, if we use HLists we will have to write the following:

val foo: Endpoint[Int :: String :: HNil, Int] = …
foo(42 :: "bar" :: HNil)

Which is less nice imho. We could support passing a tuple as parameter as well, by having an apply method taking an implicit Generic that would convert the tuple into the expected HList but then error messages in case of type mismatch will be disguised into “implicit not found” errors :(

@julienrf julienrf added scala 3 Requires features from Scala 3 and removed low-hanging fruit labels Jul 31, 2019
@julienrf
Copy link
Member

I think we should wait for Scala 3 to implement this feature. In Scala 3, tuples can be used like Shapeless’ HLists.

@harpocrates
Copy link
Collaborator

harpocrates commented Aug 13, 2020

Scala 3 tuples will indeed be nice. However, I'm not sure what the migration plan might be here, since the behaviour of Scala 3 Tupler instances would be different than the Scala 2 ones (eg. they'd be able to concatenate larger tuples). That might be a bit frustrating for projects that cross-build for a while and need the same Scala code to work across both versions.

As such, perhaps it makes sense to add an HList based Tupler now to Scala 2 (then the Shapeless dependency can be removed for the Scala 3 build since the same instances will be achievable directly with native tuples). Just to be clear: this would not mean writing val foo: Endpoint[Int :: String :: HNil, Int] = - it would just mean that the following would work on 2 via Shapeless and on 3 via native tuples.

trait MyEndpoints extends endpoints4s.algebra.Endpoints {
  def tooManyArgs: Endpoint[(Int, Int, Int, Int, Int, Int), Unit] = endpoint(
    request = post(
      url = path / "foo" / segment[Int]("i1") / segment[Int]("i2") / segment[Int]("i3"),
      entity = emptyRequest.xmap(_ => (0,1,2))(_ => ())
    ),
    response = ok(emptyResponse)
  )
}

... instead of failing with the type error

cmd3.sc:3: type mismatch;
 found   : MyEndpoints.this.Request[this.Out]
    (which expands to)  MyEndpoints.this.Request[(Int, Int, Int, (Int, Int, Int))]
 required: MyEndpoints.this.Request[(Int, Int, Int, Int, Int, Int)]
Error occurred in an application involving default arguments.
    request = post(
                  ^
Compilation Failed

@julienrf
Copy link
Member

it would just mean that the following would work on 2.12 via Shapeless and on 2.13 via native tuples.

I guess you mean “on Scala 2 via Shapeless and on Scala 3 via native tuples”. Did you make some experiments to check that the user experience would be good on Scala 2?

@harpocrates
Copy link
Collaborator

harpocrates commented Aug 16, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scala 3 Requires features from Scala 3
Projects
None yet
Development

No branches or pull requests

4 participants