macwire icon indicating copy to clipboard operation
macwire copied to clipboard

Extend cats-autowire to handle any effect type

Open adamw opened this issue 4 years ago • 20 comments

Currently autowire works only for IO. It would be great if it would:

(a) work for any F[_] (b) verify (if at all possible?) that all passed effects/factories/resources use the same effect type - or rather, that they can be parametrised with the same effect type

adamw avatar Dec 23 '21 09:12 adamw

The next step may be to verify if it is possible to add support for other return types like ZManaged or an effect that meets some requirements

mbore avatar Dec 23 '21 13:12 mbore

Supporting ZManaged is a different task - adding a parallel implementation (hopefully sharing some code) for zio. Here it's about supporting code parametrised with the effect type, so if the user provides Resource[F] for some F[_], and where we need to return Resource[F] as well.

adamw avatar Dec 23 '21 13:12 adamw

See https://github.com/softwaremill/macwire/issues/190 for zio support

adamw avatar Dec 23 '21 13:12 adamw

ok, makes sense. It would be also good to create a pure autowire implementation. https://github.com/softwaremill/macwire/issues/191

mbore avatar Dec 23 '21 13:12 mbore

~~In scala 2, in fact it's a problem like cps.~~

~~https://github.com/ThoughtWorksInc/dsl-domains-cats~~

~~In scala 3, it's a problem like cats-effect-cps.~~

~~https://github.com/typelevel/cats-effect-cps~~

~~I wrote a repo use these to implement wire.~~

~~https://github.com/scalax/ce-injection-samples~~

~~But it's not what I want. I wrote some suggestion in gitter. I hope it can have some helpful.~~

djx314 avatar Aug 16 '22 02:08 djx314

~~I think just use target effect type to support F[_] will be some difficulties.~~ ~~Wrap a case class like fs2 I think is more "type friendly". Just~~

// case class[F[_], T](model: F[T])

~~And provide a simple Monad[IO] with any target effect type, we can simple find the target class which need to inject it's constructor.~~ ~~And as the suggestion in gitter, displays the parameter need in building the constructor injection will broken something about "injection by type".~~ ~~So I think separate effect type and model type can provide a frindly ”type environment“ to solve this problem.~~

djx314 avatar Aug 18 '22 07:08 djx314

~~Just have a test and will bring back some freeback.~~ ~~Sorry for read the code with some misconceptions since I have implemented it in a way with the less correlation.~~

djx314 avatar Aug 18 '22 17:08 djx314

~~@adamw I think injection without F[_] can simply create a model like~~

// sealed trait Injection
// case class FunctionInjection(val func: Any => Injection, val input: Injection]) extends Injection
// case class ModelInjection(val value: Any) extends Injection

~~And we can tag this to F[_]. like~~

// sealed trait Injection
// case class FunctionInjection(val func: Any => Injection, val input: Injection) extends Injection
// case class EffectInjection(val effectValue: F[Injection]) extends Injection
// case class ModelInjection(val value: Any) extends Injection

~~I plan to use implicit to implement a injection since implicit in scala 2 means context so in scala 3 it calls context abstraction. So the code that in my thinking is something like the injection without cats-effect in macwire.~~

djx314 avatar Nov 17 '22 22:11 djx314

~~In the abstraction of Injection with F[_], we can no use to do something like close, release because Resource and many many things will do this for us. It seems that many things in Spring's Injection now just leave it to F[_]~~

djx314 avatar Nov 17 '22 22:11 djx314

~~Yes, like ZManaged[A & B, Nothing, C], we just print it as~~

// val a: Injection = implement ZManaged[X, X, A]
// val b: Injection = implement ZManaged[X, X, B]
// val c: Injection = FunctionInjection(func = need => genInjectionC, input = List(a, b))

~~and we just tag the info in the case class what your ast need. And than we can simply singed it ZManaged[A & B, Nothing, C] just we won't implement this injection dependent on the type in fact.~~

djx314 avatar Nov 17 '22 22:11 djx314

~~tough the email since changing the code above.~~

djx314 avatar Nov 18 '22 10:11 djx314

Hm, interesting idea - so autowire would generate a description, of how the injection should be done. And then at run-time, we can pick the appropriate effect.

adamw avatar Nov 18 '22 16:11 adamw

~~> Hm, interesting idea - so autowire would generate a description, of how the injection should be done. And then at run-time, we can pick the appropriate effect.~~

~~Just a copy of free.~~

djx314 avatar Nov 19 '22 00:11 djx314

~~> Hm, interesting idea - so autowire would generate a description, of how the injection should be done. And then at run-time, we can pick the appropriate effect.~~

~~We just add some tags in ast. like~~

// case class EffectInjection(val effectValue: F[Injection], val tag: InjectionTag) extends Injection

~~And all effect do the same thing in the ast. Just provide a execute context is ok. And all the effects use different way to target to the trait Injection.~~

djx314 avatar Nov 19 '22 01:11 djx314

~~In EffectInjection, the effect value we can point A in F[A] to an abstraction.~~

// trait EffectValue[A]
// case class RigthEffectValue[F[_], A](val effectValue: F[A]) extends EffectValue[A]
// case class EitherEffectValue[F[_, _], E, A](vall effectValue: F[E, A]) extends EffectValue[A]
// and so on

~~certainly, we can add tags to the model.~~ ~~Provide a execute context and it can works well like the trait Injection above. We no need to mind the type it signed, just set all the type to Any in execute context. Then we can~~

// case class EffectInjection(val effectValue: EffectValue[Injection], val tag: InjectionTag) extends Injection

djx314 avatar Nov 19 '22 05:11 djx314

~~Yes, distage just can do each effect target to each ast and use each match case to execute the ast. It can't make all the ast to do the same thing😉.~~

djx314 avatar Nov 19 '22 11:11 djx314

~~Change the code above.~~ ~~From~~

// case class FunctionInjection(val func: List[Injection] => Injection, val input: List[Injection]) extends Injection

~~to~~

// case class FunctionInjection(val func: List[Any] => Injection, val input: List[Injection]) extends Injection

~~though it's enough~~

djx314 avatar Nov 24 '22 19:11 djx314

~~Change the code above~~ ~~From~~

// case class FunctionInjection(val func: List[Any] => Injection, val input: List[Injection]) extends Injection

~~to~~

// case class FunctionInjection(val func: Any => Injection, val input: Injection) extends Injection

~~though List[Any] can replace with Currey, Then it's only a free.~~

djx314 avatar Dec 01 '22 16:12 djx314

@adamw Wrong, I think all is wrong.

In fact, injection have two parts. 1 is resources, and our app is just dept on part 1 and to be part 2. Part 1 is just 5 - 6 resources, use zio is ok, use cats is ok, use Future or use spirng on java is ok. And get a part 2 from part 1 to run a app is just a shapeless without F[_], or it's macwire's first release.

So if we use two step injection, part 1 can esaily solve by coder himself and part 2 is just macwire's first release.

djx314 avatar Dec 11 '22 00:12 djx314

I use the macwire(just use wire[Instance]) to implement cats-effect's cats.Resource in this demo1, demo2 with the two step injection described above.

It seems that just the simple macwire is already works well with any effect type, and this demo use some simple way to implement by name injection.

@mbore It seems that this can answer the question in Gitter😊

djx314 avatar Jan 08 '23 02:01 djx314