-
Couldn't load subscription status.
- Fork 1.4k
Implement Accessor trait for simple macro-less accessor methods #5130
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
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package zio | ||
|
|
||
| /** | ||
| * A simple, macro-less means of creating accessors from Services. Extend | ||
| * the companion object with `Accessor[ServiceName]`, then simply call | ||
| * `Companion(_.someMethod)`, to return a ZIO effect that requires the | ||
| * Service in its environment. | ||
| * | ||
| * Example: | ||
| * {{{ | ||
| * trait FooService { | ||
| * def magicNumber: UIO[Int] | ||
| * def castSpell(chant: String): UIO[Boolean] | ||
| * } | ||
| * | ||
| * object FooService extends Accessor[FooService] | ||
| * | ||
| * val example: ZIO[Has[FooService], Nothing, Unit] = | ||
| * for { | ||
| * int <- FooService(_.magicNumber) | ||
| * bool <- FooService(_.castSpell("Oogabooga!")) | ||
| * } yield () | ||
| * }}} | ||
| */ | ||
| trait Accessor[R] { | ||
| def apply[E, A](f: R => ZIO[Any, E, A])(implicit tag: Tag[R]): ZIO[Has[R], E, A] = | ||
| ZIO.serviceWith[R](f) | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamgfraser @kitlangton
My only potential concern with this was the name
Accessor, which might be pretty common.The other potential improvement we could make: warn if the user tries to use this on an effect that requires an environment.
Finally, we should probably extend all companion objects of our own services by this trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On trait name:
ServiceCompanionServiceAccessorIt could also be useful to think of other utilities which could be placed into the service companion object.
For example:
I am not sure if this utility pays for itself, but right now, using
toLayersometimes fails because of the invariance ofHas, requiring you to widen to the service in the finalyieldof theforcomprehension that builds the effect, e.g.:In the companion object, you have access to the type
Rof the service so you can add utilities that fix it.This could be changed to:
If not this one, we should look at opportunities to introduce other utilities that require the service type to be known.
/cc @kitlangton @adamgfraser
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jdegoes Yes. If we just want to use it for these accessors then perhaps we could do
Accessiblewhich I imagine would be less common but if we want to have other generic utilities related to services then something likeServiceCompanionseems more appropriate.There is a little risk that we are creating two ways to do things here (e.g.
Clock.nanotimeversusClock(_.nanotime)) so could be good to think about our messaging around this. TheClock.nanotimereads really nicely like it is just a method on a static object but does require a little more work to implement the accessors. Is this the "not quite as nice" shortcut for when you don't want to do that? Is it a replacement for the accessors?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamgfraser I like that. Good to have the same name as the macro it's going to replace (in Scala 3).
@adamgfraser That would be my argument. The default services are used in lots of places, and the difference in niceness is worth making the accessors. I was just thinking this could be useful when you likely are just going to want some less verbose way of using the accessors in test code/a small smattering of places. If you're making a Service that's generally useful and going to be accessed often, I think it's very much worth it to define the individual accessors. The motivation for this was mainly to provide a replacement for @accessible in Scala 3.
@jdegoes I think that's possible to fix if its broken, though I believe you can currently do
zio.toLayer[SuperType]to widen it at the call-site. This works for thetoLayerconversions on functions, it'll infer based on the type-signature of the val, or one can pass an type totoLayer.@jdegoes That's great! I was thinking of extending #4823 with environment related warnings. That'll be a great way to teach. We can also add links to our docs from the warnings :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made changes: #5133