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

avoid deprecated macro APIs post 2.10 #2534

Merged
merged 4 commits into from Sep 28, 2018
Merged

avoid deprecated macro APIs post 2.10 #2534

merged 4 commits into from Sep 28, 2018

Conversation

larsrh
Copy link
Contributor

@larsrh larsrh commented Sep 25, 2018

No description provided.

@@ -139,7 +139,7 @@ private[arrow] object FunctionKMacros extends MacroCompat {

private[this] def punchHole(tpe: Type): Tree = tpe match {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to take a moment to appreciate the name of this method.

@larsrh
Copy link
Contributor Author

larsrh commented Sep 26, 2018

The removed trait is private[cats]. Is it allowed to add a bincompat exception there?

@kailuowang
Copy link
Contributor

kailuowang commented Sep 26, 2018

It looks to me that this change should be bin compat (although I am not really sure since macro is involved). Regardless, I think it would be a good practice to add a test to verify that the intended end usage is still bin compat when we add a Mima exception. The PR to add such tests and related infrastructure is #2509 @larsrh would you take a look? Once that is merged, we can add one for FunctionK.lift.

Another thing, maybe I should mention it first, is that @milessabin suggested that we don't really need macro here. we can just do asInstanceOf thanks to erasure. In the following code I also made the example a doc test, and it passes.

  /**
    * Lifts function `f` of `F[A] => G[A]` into a `FunctionK[F, G]`.
    *
    * {{{
    * scala> import cats.arrow.FunctionK
    * scala> def headOption[A](list: List[A]): Option[A] = list.headOption
    * scala> val lifted: FunctionK[List, Option] = FunctionK.lift(headOption)
    * scala> lifted(List(1,2,3))
    * res0: Option[Int] = Some(1)
    * }}}
    *
    * Note: This method has a macro implementation that returns a new
    * `FunctionK` instance as follows:
    *
    * {{{
    *   new FunctionK[F, G] {
    *     def apply[A](fa: F[A]): G[A] = f(fa)
    *   }
    * }}}
    *
    * Additionally, the type parameters on `f` must not be specified.
    */
  def lift[F[_], G[_]](f: (F[α]  G[α]) forSome { type α }): FunctionK[F, G] =
    new FunctionK[F, G] {
      def apply[A](fa: F[A]): G[A] = f.asInstanceOf[F[A] => G[A]](fa)
    }

Update: Mima didn't complain about this implementation change. So if we use this asInstance instead, we can safely remove the FunctionKMacros and MacroCompat, and add the Mima exceptions for them without adding a separate bin compat test for FunctionK.lift. But still I will appreciate it if you can take a look at #2509

@kailuowang
Copy link
Contributor

kailuowang commented Sep 26, 2018

cc @andyscott who added the macro to see if he has any concerns over the asInstanceOf implementation.

@larsrh
Copy link
Contributor Author

larsrh commented Sep 26, 2018

Here's a problem with this approach:

scala> import cats.arrow._
import cats.arrow._

scala> def sample[A](option: Option[A]): List[A] = option.toList
sample: [A](option: Option[A])List[A]

scala> FunctionK.lift(sample[String])
res0: cats.arrow.FunctionK[Option,List] = cats.arrow.FunctionK$$anon$5@53cd7d41

This should supposedly be ruled out.

@kailuowang
Copy link
Contributor

How did the macro version respond, if you have tried?

@larsrh
Copy link
Contributor Author

larsrh commented Sep 26, 2018

That's checked in the test suite with assertTypeError.

Copy link
Contributor Author

@larsrh larsrh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments on changes I made along the way.

@@ -124,7 +124,7 @@ private[arrow] object FunctionKMacros extends MacroCompat {
val G = punchHole(evG.tpe)

q"""
new FunctionK[$F, $G] {
new _root_.cats.arrow.FunctionK[$F, $G] {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a hygiene issue that I fixed along the way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

"org.scalatest" %%% "scalatest" % scalatestVersion(scalaVersion.value) % Test
)
)
.dependsOn(coreJVM % Test)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize that the approach in #2509 would require a publishLocal first. This here may be simpler.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right. I was testing against existing published jars, didn't realize that I can just do module dependency.

@larsrh
Copy link
Contributor Author

larsrh commented Sep 26, 2018

@kailuowang This is still the macro solution, with bincompat tests & filters on top.

@codecov-io
Copy link

codecov-io commented Sep 26, 2018

Codecov Report

Merging #2534 into master will decrease coverage by 0.04%.
The diff coverage is 0%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2534      +/-   ##
==========================================
- Coverage   95.18%   95.14%   -0.05%     
==========================================
  Files         360      359       -1     
  Lines        6548     6548              
  Branches      279      279              
==========================================
- Hits         6233     6230       -3     
- Misses        315      318       +3
Impacted Files Coverage Δ
core/src/main/scala/cats/arrow/FunctionK.scala 100% <ø> (ø) ⬆️
...patTest/src/main/scala/catsBC/MimaExceptions.scala 0% <0%> (ø) ⬆️
testkit/src/main/scala/cats/tests/Helpers.scala 96% <0%> (-4%) ⬇️
...rc/main/scala/cats/kernel/instances/function.scala 96.96% <0%> (-3.04%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update cc8919f...8871228. Read the comment docs.

@andyscott
Copy link
Contributor

I definitely am in favor of removing the macro implementation!

@larsrh
Copy link
Contributor Author

larsrh commented Sep 27, 2018

I definitely am in favor of removing the macro implementation!

@andyscott Just to be clear, this PR doesn't do that, because the non-macro solution is unsafe.

@LukaJCB
Copy link
Member

LukaJCB commented Sep 27, 2018

I'm pretty clueless wrt macros, so I'm not sure I'm a good authority to review this PR, but I trust you two to have done the correct thing, so I think we can probably merge this :)

@larsrh
Copy link
Contributor Author

larsrh commented Sep 27, 2018

@LukaJCB I left the macro in place with minor changes, really nothing fancy happening here (@kailuowang did all the work on BC) 😄

@kailuowang kailuowang merged commit 957da66 into typelevel:master Sep 28, 2018
@larsrh larsrh deleted the topic/macros-post-2.10 branch September 28, 2018 06:28
@larsrh
Copy link
Contributor Author

larsrh commented Oct 5, 2018

For posterity: #2553 (comment)

@kailuowang kailuowang added this to the 1.5 milestone Oct 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants