I mainly write rust, but scala, being arguably more open to different paradigms than rust, does functional programming so well. I really hope ergonomic HKT's will be added to rust one day.
Daniel, no offence at all but im gonno say it....this video is better than the 'handling failure' on your beginner course. Its all making sense now after watching this.
Thanks for the explanation! I was thinking that the fact that does not have `flatMap` means that we can do `.mapN(` and parallelize all the validations.
Good video. I was initially a Java dev and moved to Scala a few years ago. I kept some bad habits such as using the first method here. I will be switching to cats for this and see what else they have. Your cats course sounds interesting.
Aah I was really excited for the Validated data type (because Either feels more like a Sum type rather than a Ok/Err data structure and the fact that it's left/right not wrong/right gives me an aneurysm xD), but I'm disappointed it's not a monad since I love chaining conditions in for comprehensions. Do you think that if I were to learn Cats and include it in my projects I would have to code in the idiomatic "purely" functional Cats way or can I use what I need from there without turning it into a religion?
You can see cats either as a tool-box of common functionalities (like Validated) or as building blocks for writing fully parametrized code (or the so-called tagless final style). The amazing thing is, much like Scala, is not an either one or the another but rather a spectrum, so you can move inside it freely as you please.
Great video, but I believe it would have been better to expand a bit more on the Validated part. First, it is common to use a non-empty collection for the invalid case, since if you have an invalid is because you have at least one error. And since you will be concatenating errors together then it makes sense to use something that it's optimized for that; enter NonEmptyChain - also, this is so common that we have type ValidatedNec[E, A] = Validated[NonEmptyChain[E], A] Second, Validated does provide a flatMap like method (since it is isomorphic with Either) it just uses a different name for convention, it is called andThen. Third, the two most common ways of using Validated are not using combine, rather using mapN or traverse - The first one, to combine multiple independent validations such that we apply a function if all values are valid or we combine all invalids; e.g (validateName(rawName, validateAge(rawAge)).mapN { case (name, age) => Person(name, age) } . The second one, is used to "reduce" a list of independent validations into a list of valid values, if all are valid, or collect all the errors; e.g. List(1, 2, 3).traverse(validateEven) Last but not least, it is now recommended to not use Validated directly but rather use the parallel instance of Either. That way, you can use only a single datatype and chose if compose the validations in a fail-fast or accumulating semantics on each use site. Basically by using flatMap for the former and combinators like parMapN or parTraverse for the later.
Thanks for the feedback - here are my thoughts: 1. For the Nec thing, my goal is to keep complexity to a minimum since I expect most watchers are not familiar with Validated at all. 2. andThen is not the same as flatMap, because it short-circuits error accumulation - the name is appropriate and the Applicative (not Monad) property stands 3. Again, for the sake of minimizing complexity for people not familiar with Validated. I'll probably add a dedicated video on validation and traversal. 4. I'll probably add more nuance in another more advanced/subtle video.
@@rockthejvm yeah I believe an in-depth video about Validated and Either + Parallel would be great! "andThen is not the same as flatMap, because it short-circuits error accumulation" Yeah, that is exactly the point, andThen behaves exactly as flatMap would behave. You can not accumulate errors on a flatMap call, because if you have v1.flatMap(f) and v1 failed you can not call f so it can't fail, also if f fails is because v1 succeded; as such there doesn't make sense to combine errors because there can never be two, only one. Is not called flatMap, because by convention flatMap has to be coherent with ap but this is not the case and to be coherent we would need to change ap, which would lose the whole point of Validated.
Exception means something exceptional happened and program must do something about it. Often we report & exit the app. However i don't understand the logic for every try-catch as an expression. If we are supposed to read a file and file is not there we must exit, what's the point of using try-catch expression if we cannot continue ?
Identity is a single-arg function. Here we need two arguments. Semigroup is a math term, where you have a set of items (for us, a type), and a combination function which turns two arguments from the set/type into another value from the set/type.
> Left side is undesirable, Right side is desirable WHY is this convention not more prominent in all places talking about Either. More often I read descriptions about this being unbiased and that either (hehe) side has equal values. Thanks a lot
I mainly write rust, but scala, being arguably more open to different paradigms than rust, does functional programming so well. I really hope ergonomic HKT's will be added to rust one day.
Daniel, no offence at all but im gonno say it....this video is better than the 'handling failure' on your beginner course. Its all making sense now after watching this.
Glad it finally does - I'm redoing the beginner course for Scala 3.
Brilliantly explained. Loved the build up of pros and cons
Wow! I have seen Validated for the first time and I'm quite impressed with the power of functional programming :D Thanks for an awesome video!
Glad it helps!
Thanks for the explanation! I was thinking that the fact that does not have `flatMap` means that we can do `.mapN(` and parallelize all the validations.
Thank you Daniel, best explanation I found about Validated. You just forget to mention Fold method of Either that I find very useful.
Glad it helps - of course, the API is quite comprehensive.
thats a hard one, thanks for the great explanation
Good video. I was initially a Java dev and moved to Scala a few years ago. I kept some bad habits such as using the first method here. I will be switching to cats for this and see what else they have. Your cats course sounds interesting.
Glad it's useful!
Aah I was really excited for the Validated data type (because Either feels more like a Sum type rather than a Ok/Err data structure and the fact that it's left/right not wrong/right gives me an aneurysm xD), but I'm disappointed it's not a monad since I love chaining conditions in for comprehensions. Do you think that if I were to learn Cats and include it in my projects I would have to code in the idiomatic "purely" functional Cats way or can I use what I need from there without turning it into a religion?
Not really - Cats is quite flexible.
You can see cats either as a tool-box of common functionalities (like Validated) or as building blocks for writing fully parametrized code (or the so-called tagless final style). The amazing thing is, much like Scala, is not an either one or the another but rather a spectrum, so you can move inside it freely as you please.
Great video, but I believe it would have been better to expand a bit more on the Validated part.
First, it is common to use a non-empty collection for the invalid case, since if you have an invalid is because you have at least one error. And since you will be concatenating errors together then it makes sense to use something that it's optimized for that; enter NonEmptyChain - also, this is so common that we have type ValidatedNec[E, A] = Validated[NonEmptyChain[E], A]
Second, Validated does provide a flatMap like method (since it is isomorphic with Either) it just uses a different name for convention, it is called andThen.
Third, the two most common ways of using Validated are not using combine, rather using mapN or traverse - The first one, to combine multiple independent validations such that we apply a function if all values are valid or we combine all invalids; e.g (validateName(rawName, validateAge(rawAge)).mapN { case (name, age) => Person(name, age) } . The second one, is used to "reduce" a list of independent validations into a list of valid values, if all are valid, or collect all the errors; e.g. List(1, 2, 3).traverse(validateEven)
Last but not least, it is now recommended to not use Validated directly but rather use the parallel instance of Either. That way, you can use only a single datatype and chose if compose the validations in a fail-fast or accumulating semantics on each use site. Basically by using flatMap for the former and combinators like parMapN or parTraverse for the later.
Thanks for the feedback - here are my thoughts:
1. For the Nec thing, my goal is to keep complexity to a minimum since I expect most watchers are not familiar with Validated at all.
2. andThen is not the same as flatMap, because it short-circuits error accumulation - the name is appropriate and the Applicative (not Monad) property stands
3. Again, for the sake of minimizing complexity for people not familiar with Validated. I'll probably add a dedicated video on validation and traversal.
4. I'll probably add more nuance in another more advanced/subtle video.
@@rockthejvm yeah I believe an in-depth video about Validated and Either + Parallel would be great!
"andThen is not the same as flatMap, because it short-circuits error accumulation"
Yeah, that is exactly the point, andThen behaves exactly as flatMap would behave. You can not accumulate errors on a flatMap call, because if you have v1.flatMap(f) and v1 failed you can not call f so it can't fail, also if f fails is because v1 succeded; as such there doesn't make sense to combine errors because there can never be two, only one.
Is not called flatMap, because by convention flatMap has to be coherent with ap but this is not the case and to be coherent we would need to change ap, which would lose the whole point of Validated.
Exception means something exceptional happened and program must do something about it. Often we report & exit the app. However i don't understand the logic for every try-catch as an expression. If we are supposed to read a file and file is not there we must exit, what's the point of using try-catch expression if we cannot continue ?
Exceptions are not the end of the world - even in Java you have try-catches to recover from error. Here in Scala, the entire thing returns a value.
24:19 - maybe it would make more sense to have a Semigroup (where this names comes from???) with identity?
Identity is a single-arg function. Here we need two arguments.
Semigroup is a math term, where you have a set of items (for us, a type), and a combination function which turns two arguments from the set/type into another value from the set/type.
@@rockthejvm Thanks for explanation!
great explanation, thanks
> Left side is undesirable, Right side is desirable
WHY is this convention not more prominent in all places talking about Either. More often I read descriptions about this being unbiased and that either (hehe) side has equal values.
Thanks a lot
Either was not originally intended for error handling, but ended up widely used for this purpose.
@@rockthejvm Ha! I figured that was the case, after seeing this video among other things. Thanks for your great content and this answer
Awesome
:D
Rocket science is easy. Rocket engineering on the other hand...
:D
Rocket surgery is very very hard
Where is the UFO operator? If I remember well: |@|
I'll probably talk about semigroups and monoids in another video.