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

Update cats-mtl to 1.0.0 #18

Merged
merged 2 commits into from
Jul 2, 2021
Merged

Update cats-mtl to 1.0.0 #18

merged 2 commits into from
Jul 2, 2021

Conversation

kubukoz
Copy link
Contributor

@kubukoz kubukoz commented Oct 7, 2020

So far the compile-time derivation suites don't compile (might have to do something with the fact that the MonadPartialOrder-based derivations are now in implicit scope by default), but everything else does. Laws and monix tests pass.

@oleg-py do you have any ideas on how to best approach the derivations now? I can do some thinking but maybe you already have something.

@SethTisue
Copy link

👀

over in scala/community-build#1231, I'll need to temporarily remove meow-mtl and pfps-shopping-cart from the community build until this is resolved

@kubukoz
Copy link
Contributor Author

kubukoz commented Oct 12, 2020

@oleg-py I narrowed the issue down to variance - Ask[F[_], +A] seems to be the culprit. I briefly explained it on https://gitter.im/typelevel/cats-mtl?at=5f7f0aca46035474840876ec.

@oleg-py
Copy link
Owner

oleg-py commented Oct 16, 2020

I've been looking into it on my own, big thanks for the pointer towards variance, didn't figure that out.

There's a silly workaround to this, you can have an alias

type IAsk[F[_], E] = Ask[F, E]

and if used everywhere, the implicit resolution won't dealias it until it actually successfully finds an implicit for derivation if there can be one. That would require user to use IAsk too, though, losing the seamless experience. At this point might as well just newtype every cats-mtl typeclass and scrap all the confusing fragile machinery like IsAbstract[F]. I'm not using much of meow-mtl myself for that to hurt me, but that could hurt libraries depending on cats-mtl where meow provides a nice interop layer if there are any. Any preferences?

@kubukoz
Copy link
Contributor Author

kubukoz commented Oct 16, 2020

I think I'd be fine with an invariant alias, as long as it's added to upstream (cats-mtl). As a library author, you could require that, but internally use the covariant one, hopefully with good user ergonomics...

I'm mildly 👎 on newtyping. I would still try to find some variance gods who can make it "just work" with the existing signatures...

Maybe even something like "giving the compiler a hint to avoid inferring the root type as the element type" would do the trick.

@oleg-py
Copy link
Owner

oleg-py commented Oct 23, 2020

I don't really want to push for aliases in cats-mtl, nor am I a variance god :D I've also ran into issues with local/ask conflicts that I'm not sure how to solve.

Probably the best way would be to fold this into cats-mtl, or make it a module with only few hook implicits in the main, so I can abandon the worst bits of machinery, but I'm not sure if guys over there are interested :)

@kubukoz
Copy link
Contributor Author

kubukoz commented Nov 9, 2020

Another idea: making all the derivations explicit methods. This might allow getting rid of the IsAbstract constraint too (but I'm not sure). Probably involves some compilation speedups as well. What do you think?

We should eventually move on with this, or decide on a different fate of meow-mtl - my team relies on it quite often for tests, so a clear future would be desirable 😅

@joroKr21
Copy link

You could try to remove MkLensToType.refl instead of using =:!= - is it integral to make it work?

@joroKr21
Copy link

The problem:

  • Ask[F[_], +A] is covariant
  • When we look for Ask[F, Foo], A is not instantiated to Foo
  • What if we find Ask[F, Bar] where Bar <:< Foo?
  • Therefore we know only that A <:< Foo
  • If A is not instantiated we cannot prove S =:!= A

@kubukoz
Copy link
Contributor Author

kubukoz commented Mar 27, 2021

We could just encourage users to manually supply the types they want to derive for.

In scala 2.13:

import scala.util.chaining._

deriveAsk[F, Parent, Child].pipe { implicit ask =>
  ...
}

It's not perfect, but it works. We could also have a variant that only requires F, Child as Parent can be inferred (weirdly enough, I couldn't get it to work for a universal F)

@oleg-py
Copy link
Owner

oleg-py commented Mar 27, 2021

@joroKr21 good suggestion, but I wasn't able to make it work.

@kubukoz at this point I'm considering jumping into Scala 3 only, since this whole machinery would have to be written differently. My preliminary testing shows that:

  • Diverging implicits are a non-issue in Scala 3, so stuff like IsAbstract and =!:= isn't needed
  • I can get away with a single macro to make a lens instead of inductive instances, so I can even drop shapeless dependency.

Of course, relying on Scala 3 implicit resolution changes scraps any possibility of cross-compilation to 2.13 while using automatic derivation. I can probably publish a migration version where you can supply types manually. I don't like that style at all tho 😓. Maybe it would work by making instances non-implicit and requiring a user to write an implicit def in the companion of Child.

@kubukoz
Copy link
Contributor Author

kubukoz commented Apr 1, 2021

I like this idea:

Maybe it would work by making instances non-implicit and requiring a user to write an implicit def in the companion of Child.

It's probably the least friction.

@joroKr21
Copy link

joroKr21 commented Apr 18, 2021

Have you considered proposing upstream to make Ask invariant again?
Btw even just a type alias type MeowAsk[F[_], A] = Ask[F, A] works, but it still requires users to work with MeowAsk.

There's a silly workaround to this, you can have an alias type IAsk[F[_], E] = Ask[F, E] and if used everywhere, the implicit resolution won't dealias it until it actually successfully finds an implicit for derivation if there can be one.

Actually you don't have to use it everywhere, ironically only users have to use it in order to fix E before kicking off the implicit search.

@oleg-py
Copy link
Owner

oleg-py commented Apr 19, 2021

Have you considered proposing upstream to make Ask invariant again?

Actually, I don't think that's the right way to go. Ask variance makes sense there, it's just, ugh, fragile implicit-macro machinery doesn't handle that too well, which is meow-mtl problem, not cats-mtl problem.

Actually you don't have to use it everywhere, ironically only users have to use it in order to fix E before kicking off the implicit search.

Yeah, that's what I meant by "if used everywhere". But I don't see that as a solution either.


It's possible that a handwritten lens macro will work better than shapeless magic in Scala 2 as well. Though I need to muster a lot of motivation to actually write one, ugh.

@joroKr21
Copy link

It's not that macro that is fragile though - it's implicit resolution for covariant / contravariant types

@mrobakowski
Copy link
Contributor

mrobakowski commented Jun 27, 2021

I had an idea how on to fix the Ask derivation problem with one naughty macro so I gave it a try in #20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants