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

ZIO Core: Add Named Aliases for ZLayer Operators #3116

Merged
merged 2 commits into from
Mar 12, 2020
Merged

ZIO Core: Add Named Aliases for ZLayer Operators #3116

merged 2 commits into from
Mar 12, 2020

Conversation

adamgfraser
Copy link
Contributor

Adds andThen as named alias for >>> and zip as named alias for ++.

/**
* A named alias for `>>>`.
*/
def andThen[E1 >: E, ROut2](that: ZLayer[ROut, E1, ROut2]): ZLayer[RIn, E1, ROut2] =
Copy link
Member

Choose a reason for hiding this comment

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

How about injectInto or injectTo?

/**
* A named alias for `++`.
*/
def zip[E1 >: E, RIn2, ROut1 >: ROut, ROut2 <: Has[_]](
Copy link
Member

Choose a reason for hiding this comment

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

How about and or maybe combine?

Clock.live and System.live and (HttpClient.live injectInto StorageAPI.live)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. We could also do to for >>> so they were both short.

Copy link
Member

Choose a reason for hiding this comment

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

👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

/**
* A named alias for `++`.
*/
def and[E1 >: E, RIn2, ROut1 >: ROut, ROut2 <: Has[_]](
Copy link
Member

Choose a reason for hiding this comment

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

Not to delay further but I'm not sure they are alphabetized. I'll approve though!

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 think they are but and just appears far down in the file because it is in the syntax class that provides evidence that the output type is a subtype of Has[_].

@adamgfraser adamgfraser merged commit 1698b89 into zio:master Mar 12, 2020
@adamgfraser adamgfraser deleted the alias branch March 13, 2020 20:42
@HansBrende
Copy link

@adamgfraser @jdegoes just found this PR because I was looking through the recent source code changes and was going to suggest that andThen would make more sense to me than to (mirroring scala's Function1.andThen), but now I see that that was the original name.

Honestly even through would make more sense to me than to (mirroring fs2 streams' syntax).

Given a choice between >>> and to, >>> wins, even if I hypothetically didn't like symbolic operators.

to is a word that usually makes the most sense to me when describing ranges (e.g. 1 to 10). Or a transformation from one datatype into another (e.g. toString). But not one that makes sense to me when we are talking about composing two things together in a transitive manner, i.e. (F[A, B], F[B, C]) => F[A, C]. That looks like an andThen to me.

@HansBrende
Copy link

HansBrende commented Mar 17, 2020

@adamgfraser @jdegoes I could potentially see into making sense as well, because you are injecting the first layer "into" the second layer, in a manner of speaking (but injecting the first layer "to" the second layer doesn't even make sense in english, IMO).

@adamgfraser
Copy link
Contributor Author

@HansBrende As you say, andThen is the idiomatic name for what a function with that signature would be called elsewhere in ZIO (e.g. TestAspect#andThen). I think the thought process here was to pick a name that was more specific to this domain to help people use layers who may not be coming from that functional programming background where arrows as generalizations of functions makes sense.

I think the idea of to is that you are taking the output of the first layer and sending it to the input of the second layer. I don't think through works since the input is just going to the second layer, it isn't also being output by the second layer unless you use separate combinators. into could work as well though seems slightly less clear to me as the output of the first layer isn't really going "inside of" the second layer but is being used an input to it.

We also still have >>> and ++ which I would consider to be the most idiomatic operators to work with layers unless for some reason you or your team really don't like symbolic operators.

So I guess my initial thought would be we picked a name for this and move on but if we wanted to revisit we could change to into.

@HansBrende
Copy link

Works for me, just thought I'd throw out my 2 cents in case it sparked something. :)

@adamgfraser
Copy link
Contributor Author

Appreciate you sharing your thoughts! If other people like into more we can definitely change and before 1.0 is the time.

@HansBrende
Copy link

@adamgfraser

I don't think through works since the input is just going to the second layer, it isn't also being output by the second layer unless you use separate combinators.

That actually brings up a completely unrelated question I have for you. I keep finding myself using the following pattern:

someRLayer[A, B] >>> (ZLayer.requires[B] ++ someRLayer[B, C])

in order to get an RLayer[A, B with C], and that through that you just mentioned sounds like it would do exactly that. Any plans on adding something like that in the future to reduce the boilerplate?

@adamgfraser
Copy link
Contributor Author

@HansBrende We just added a passthrough combinator for that.

The thing to think through there is whether you want to expose the B dependency like that. There are different philosophies about this. Some people like to pass the dependencies through like this. Others like to hide the dependency to have greater encapsulation (e.g. your Mail service may need Authentication but the may service implementation handles all that internally so the clients don't need to know anything about the mail service's dependencies). Obviously that isn't always possible if B really is needed in other parts of the dependency graph.

The default with layers is that dependencies aren't passed through but you can use passthrough if you do want that behavior.

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.

3 participants