Devreal

Effects types in Scala - how to choose o...

Event: Scale by the Bay

Scale By The Bay 2018: Alexandre Bergeron, Effects types in Scala - how to choose one

Recording: Scale By The Bay 2018: Alexandre Bergeron, Effects types in Scala - how to choose one

you so I work at Briscoe data where we are building platform for data analysts to build dashboards by typing sequel we are airing we are so not doing scholar but if you are interested in working for Chinese and positive group with a kind and positive group of engineers come talk to me after the tout all right so first I'm there's a lot of things I'm not going to address during this talk because there's a lot of effects types and it's easy to get lost in some details I'm not going to you're not going to leave here knowing which library is the best because they all have different characteristics and rather focus on what are their differences I'm not really going to talk about performance outside of both cats effect and IO are pretty much at neck-to-neck in terms of performance benchmarks actually both communities tends to work with one another to make sure that performance improvements in one libraries will be reflected in the other ones I'm also not really going to talk about what people say on Twitter and our code of contracts make people react people tend to develop strong opinions about that and that wouldn't really make a great dark if I just focus on that so I'm really going to focus on why there's so many different libraries and what is different between all of these different libraries and you might be wondering why would you use an effect type in the first place you could just write println just connect to a web server in a blocking way put results in the console and do everything in a single thread well all the reason we're doing everything in the single thread then everything will be blocking and slow and you end up not really having a lot of control over what is happening inside of your application and being able to represent that two different types makes it a lot easier to have a good understanding of what is happening when and ultimately you can't just compose all of these types that you're building together to compose bigger programs from small programs it also abstract over however you're running you know your different effects you can write something and run it in Java in a given trait pool and then run it and JavaScript in the event loop without possibility to block anything and it's easy using these effects type to just write some functions that are not necessarily tail recursive but exposes a an effect type outside of it and then it will be evaluated on a trampoline so you'll be sure that it's not going to explode your stack first off I just want to talk a little bit about futures because some of you might be more familiar with futures and thinking why should I view something that's like a future but lazy so table thing when we're talking about futures we are talking about a computation that is already running somewhere in the system and that it's result one it's computed it will be memorized and from there when you can assign a callback to a future it's going either to be called as soon as a future the results is known or immediately if the result is already known these features can definitely compose together using map and flatmap and so if you have a function that returns a future and another one that takes that result and returns another future then you have a function from a to future of C and it's pretty easy to compose these functions together and it's when it came out in Scala it was very powerful because it empowers people to easily write a synchronous non-blocking reactive applications if you will and anyway that was a lot easier to compose then through callbacks or other models and ultimately when you have a future you can always block on it but you have something that allows you to have an asynchronous computation running and you can ensure that you can act upon it a synchronously so there's not really an interest of locking unless you like racing threads and making it an ark to understand what's happening your running application so there's two main implementations of futures that are known in skeletor's a lot more than two but most importantly there's the one that is provided in the standard scale a library which its main characteristic is that it's non cancelable and that it's backed by the scalar execution context which typically is just a wrapper around a Java executor sort of a typical Java tread pool Twitter have their own implementations of scale of you of futures which predates this capsule implementation between characteristic it's that it's backed by finical and that it's also cancelable personally if you're I would say that if you're interested in using futures and you're not really invested in the Twitter stack this tower future might be easier to use this because it's just a lot more supported and the Twitter futures are really meant for what Twitter needed to do with futures not that they're bad just that they're not as openly used in the larger community as I said futures are not really an effect type we are for some reasons more importantly a future is ah is already running and when you try to compose a computations on these futures they won't break referential transparency by that I mean that if you have an effect that yet let's say a random number or that might always yield a different result and build competitions to together you might not end up with the same result if you using an actual effect type and evaluating that effect independently you will always get the same result if you're reading from the same future because at that point you'll be reading a value and not an effect so this ultimately futures will bother to bundle together a computation value and error handling and that makes it a pretty powerful type or running effect but it's not really a good type to represent effect ultimately the fact that it means that you have an effect that is running also makes it a lot harder to optimize let's say that you have a future and then you map it and then map it and then map it all of these invocations of map needs to create another future that then you have no idea whether it's running synchronously or not and then you need to run all of these futures are in possibly different threads if you're doing this on an effect type the libraries will be smart enough to realize that you can just do a composition and just take that effect then run all of these 3d maps in one other thread in a way that's a lot more efficient so a quick note a lot of you might have heard that you're when you're building using effects type you should not evaluate your effects until the end of the world they're good it might be confusing to some ultimately what people say by the end of the world is as late as possible but when it's necessary let's say that you're writing an application using the play framework and you need to return the future to to the library it's perfectly fine to evaluate your effect in the future at the end of your request if you're able to build your entire application in effects then it's perfectly fine to evaluate in the main loop of reification most of these libraries will actually provide you with a safe app tray that allows you to simply write a function that returns an effect and evaluate it in a safe way you ultimately should decide when you want to evaluate these effects and in the way that is the most reasonable for your code base we're all at different places and running everything in the same tread to not running anything until the main loop spectrum so feel free to do what seems right in your use case the first effect type that I mean the first real effect type that I'm aware of in Scala is the one that came from scale said named IO it's literally a simulation of an IO monad this is the only time I'm using that word in that talk by the way the only thing it really does is that it wraps a computation in an IO type and then it will evaluate it synchronously at the very end you get that that way it ensures that if you're doing the things that well return our other isles then there will be evaluated to a trampoline in a safe way and you can evaluate it and a safe app as I've mentioned but it's free minimalistic there is no explicit support for asynchronous boy flows in that type it's really meant for simple use cases and ultimately at least as far as I can tell I haven't seen much adoption of that type but then Scala said came with the task abstraction which is a little complex if you take a look at the code it seems to be abstracting over some future of trouble and a and eared future it refers to ask a lousy future which is something of a low-level invitation that is compared to usual future is meant to be lazy and ultimately it's only there to implement their skills at seven tasks and the fact that is users something like that and to represent a synchronous workflows and that that means that if you have a web server that's all that's a library that is a synchronous but implementing it in Java and it returns to you a call back then you can bind it into that and get a task out of it and then you can evaluate it you can unsafe perform a sink and run it a synchronously passing in a callback which ensures that you're not blocking that you're not necessarily blocking the street that you're using to call that it's executed to something called a strategy which when you take a look at the code it's also an abstraction on top of an exam executor service and it was a lot more popular then at least from I've seen then desk Allah said I oh of course as in the past few years as jut effect and said IO came out the users of scales at 7:00 dropped dramatically and right now it's somewhat mostly using more logistical base if you will something that's a lot more modern is cat effect IO which recently at its recent one that all of its library that this is a fact I've that is even more powerful I'd say then generally fixed type mostly because it supports also cancelable IO and that it's made from the start to be running in whatever makes sense where you are running your school application if you're running on Java is going to use an executor service in the background that is typically provided through I think just as of one that or rc2 because that's what my I remember your timer I think there's shift context in the latest version I don't remember the exact name but if you're running that on JavaScript it's going to use set timeout to bring this these computations and run them when the event loop is freed it has a really great support from the type level community it's used in a lot of libraries you might have heard of like FS - its TP 4s do be the one library haven't mentioned is monix but something that's of interest monix as its own task immigrant asian which predates cats effect but ultimately the maintainer of ma the main maintainer of monix is one of the main contributors to cats effect so these two types are effectively freely equivalent there are some slight differences in monix tasks that makes it a lot of sense if you're using monix and if you're using Mannix by all means use their tasks as much as possible if not probably cat affected might be better abstraction for you and it's a really powerful library it's I've used it at my Pierce company and it was really a joy to to use and it works really great and I was pretty happy to use it but more recently a new library came out called said I'll that it is real that came out with a really strong message of being very pure and representing all of your error types in a way that is included to the type something that's different that is as two types parameters which allows you to encode the fact that you know I will never fail you can actually just throw an exception in there and then it will just throw an exception but you've made kind of made it live in a way but you can also encode this clearly in the I'll type the fact that there is a possibility that it might fail you might even return let's say a string if you want to return an error message or your own error types you can even encode their site that it's an isle of nothing to say that never cannot terminate and I've note someone implemented a cat bio implementation which takes this idea of having an i/o type that is implemented through a by functor but implements it purely on the cats just effect type last act but the main things that are of note of said I was at it as a really strong focus on purity and that at least when I was learning about the IO I couldn't see anywhere in the documentation a way to evaluate the IO effect outside of your main loop this is actually false just need to read a lot of little bass at this point in this project is known as material sketch effect and it's documentation well it's a lot better than what it was for skills so it's still need you're still required to read the code base to really understand how things are happening and I but ultimately if you really value purity and you believe that these this idea of having an error track type represented at the type system then feel free to do tap to use that library and at the end of the day you'll end up with a program that will probably have some synchronicity that will returns just a callback sometimes it's going to return a skill of future because you're using a library sometimes it's going to return an effect type could be catified could be zio and it can become somewhat messy if you have all of these types interacting with each other the good news is that both Ches effect ends at i/o I have functions to easily take a future wrap it in an IO to defer its evaluation until required and ultimately take its value and put it back into its effect type to lower the amount of different types that you have to deal with in your system and sorry and it makes it it makes it really easy to add up these types in your system that's already using different types and it's actually pretty powerful to be able to involve your code base going from using futures everywhere to using filters in your legacy code base and when an Oracle base that might be using just affect legs let's say need to interact with that political base then you can just wrap it there and I follow your effects in a way to execute it in a way that's predictable but that still leaves situations where you might end up implementing something without doing what type you're going to use and for that test effect implemented a set of type classes that represent the different effects that you I if they're armed and it's these type lasses are pretty like and represent cases where you have an effect that will be running synchronously or asynchronously or do you have effects that will be coming to each other and you might want to race to different effects and yet the first result there's a lot of these different type classes there's pretty solid documentation and it is really easy to use that and then get an IO type of the order of that and also said I'll provides its own type classes instance for that particular type it doesn't provide instances for every single type classes out there but it still makes it easier to use another type and even if you really want to use pasilla seven effect like IO or task there's a library called shams which provides you with these type classes instances to be able to let's say run your more modern codebase in a more older effect type if you need that that is all the what I had for you I just I went I'll just put it bigger I very quick I've had actually four different hello worlds that are implemented in chat effect and said IO the first one is simply a naive implementation using chat effect we have sorry okay let me just all right that should look good all right the first one just nicely wrapped a string in an aisle type and then flat flat maps into a println that is run a synchronously lazily and then we are running it by blocking it same thing for scenario here we are guaranteed to never crash but it's been the same implementation where I get a pure Ella weld and run it synchronously true that IO I'm telling it to your function Club unsafe run or it's I can get because I'm extending the RTS which is based on my understanding what Jedi Oh uses as its runtime environment and usually if you want to execute miles outside of main this is all you should this is the only way I figured out I'll to do it with Jedi oh and here I have a very abstract let's say let's guys like that implementation of an alien world that uses and it anything that just provides me with a sink type class and from there I I just as usual just wrap that value in a pure in a pure instance of that and then flat map over it and represent and delay the evaluation of printer land and from there I'm able to get an equivalent people in recent for cats effect and yet that equivalent for tasks which is something that zio provides to ensure that it's two priority meters fits into a tightness that expects one parameter and ultimately I'm just running it unsafely and if I call it to the command line well there's some mornings but it's prints it friends different worst of all worlds that's all add for you thank you very much for listening any questions [Applause] like I'm telling bias because I I've added cats a fact that my Prius company and it's the one I feel the most familiar building systems quickly I do insist that my goal of this talk is not to leave any one of the feeling that I think anyone is any one of these libraries are best so yeah