Update deeply nested case class with Options - scala

I have a 3-level nested case class model with a bunch of options that represents some data in a database. It's essentially:
case class User(settings: Option[Settings])
case class Settings(keys: Option[List[KeySet]])
case class KeySet(privateKey: String, publicKey: String)
I understand how to get deeply nested fields out of this using some for comprehension or chains of flatMap (Scala Option object inside another Option object) and I also understand how to update it using a lens library, but I want to figure out how to update the fields even if some stuff in the tree is None and automatically make Somes of those if they don't exist yet.
For example, how would I handle the case where I want to add to the keys List but the user hasn't yet set any settings? Is it possible to, in some sense, automatically create a Some(settings) field and also a Some(keys) field?
I have an idea of how to do it with a lot of pattern matching, but this seems wrong because of 1. rightward drift of code and 2. not using map or flatMap very much with the options.
Is this possible using a lens library on its own? I read here that it might not be possible: https://github.com/julien-truffaut/Monocle/issues/215 as in the case of Monocle it can't update an Option that is a None. Maybe I need to think about the problem another way?
Thanks

I'm not sure why you use Option[List[KeySet]]. Is there an important distinction between None and an empty List?
In any case, I find fold to be a handy tool when working with Options.
def updateUser(u :User, ks :KeySet) :User = {
u.copy(settings =
Some(u.settings.fold(Settings(Some(ks::Nil))) (stngs =>
stngs.copy(keys = Some(stngs.keys.fold(ks::Nil) (ks::_))))))
}
val pat = updateUser(User(None), KeySet("a","b"))
//pat: User = User(Some(Settings(Some(List(KeySet(a,b))))))
val upat = updateUser(pat, KeySet("c","d"))
//upat: User = User(Some(Settings(Some(List(KeySet(c,d), KeySet(a,b))))))

Related

How to use Scala Cats Validated the correct way?

Following is my use case
I am using Cats for validation of my config. My config file is in json.
I deserialize my config file to my case class Config using lift-json and then validate it using Cats. I am using this as a guide.
My motive for using Cats is to collect all errors iff present at time of validation.
My problem is the examples given in the guide, are of the type
case class Person(name: String, age: Int)
def validatePerson(name: String, age: Int): ValidationResult[Person] = {
(validateName(name),validate(age)).mapN(Person)
}
But in my case I already deserialized my config into my case class ( below is a sample ) and then I am passing it for validation
case class Config(source: List[String], dest: List[String], extra: List[String])
def vaildateConfig(config: Config): ValidationResult[Config] = {
(validateSource(config.source), validateDestination(config.dest))
.mapN { case _ => config }
}
The difference here is mapN { case _ => config }. As I already have a config if everything is valid I dont want to create the config anew from its members. This arises as I am passing config to validate function not it's members.
A person at my workplace told me this is not the correct way, as Cats Validated provides a way to construct an object if its members are valid. The object should not exist or should not be constructible if its members are invalid. Which makes complete sense to me.
So should I make any changes ? Is the above I'm doing acceptable ?
PS : The above Config is just an example, my real config can have other case classes as its members which themselves can depend on other case classes.
One of the central goals of the kind of programming promoted by libraries like Cats is to make invalid states unrepresentable. In a perfect world, according to this philosophy, it would be impossible to create an instance of Config with invalid member data (through the use of a library like Refined, where complex constraints can be expressed in and tracked by the type system, or simply by hiding unsafe constructors). In a slightly less perfect world, it might still be possible to construct invalid instances of Config, but discouraged, e.g. through the use of safe constructors (like your validatePerson method for Person).
It sounds like you're in an even less perfect world where you have instances of Config that may or may not contain invalid data, and you want to validate them to get "new" instances of Config that you know are valid. This is totally possible, and in some cases reasonable, and your validateConfig method is a perfectly legitimate way to solve this problem, if you're stuck in that imperfect world.
The downside, though, is that the compiler can't track the difference between the already-validated Config instances and the not-yet-validated ones. You'll have Config instances floating around in your program, and if you want to know whether they've already been validated or not, you'll have to trace through all the places they could have come from. In some contexts this might be just fine, but for large or complex programs it's not ideal.
To sum up: ideally you'd validate Config instances whenever they are created (possibly even making it impossible to create invalid ones), so that you don't have to remember whether any given Config is good or not—the type system can remember for you. If that's not possible, because of e.g. APIs or definitions you don't control, or if it just seems too burdensome for a simple use case, what you're doing with validateConfig is totally reasonable.
As a footnote, since you say above that you're interested in looking in more detail at Refined, what it provides for you in a situation like this is a way to avoid even more functions of the shape A => ValidationResult[A]. Right now your validateName method, for example, probably takes a String and returns a ValidationResult[String]. You can make exactly the same argument against this signature as I have against Config => ValidationResult[Config] above—once you're working with the result (by mapping a function over the Validated or whatever), you just have a string, and the type doesn't tell you that it's already been validated.
What Refined allows you to do is write a method like this:
def validateName(in: String): ValidationResult[Refined[String, SomeProperty]] = ...
…where SomeProperty might specify a minimum length, or the fact that the string matches a particular regular expression, etc. The important point is that you're not validating a String and returning a String that only you know something about—you're validating a String and returning a String that the compiler knows something about (via the Refined[A, Prop] wrapper).
Again, this may be (okay, probably is) overkill for your use case—you just might find it nice to know that you can push this principle (tracking validation in types) even further down through your program.

Traversing Scalaz Tree

I'm trying to understand the scalaz tree structure and am having some difficulty!
First I've defined a tree:
val tree: Tree[Int] =
1.node(
2.leaf,
3.node(
4.leaf,
5.leaf))
So far using TreeLoc I've worked out how to find the first element that matches some predicate. E.g. to find the first node where the value is 3:
tree.loc.find(x => x.getLabel == 3)
My next challenge was to try and find all nodes that match some predicate. For example I would like to find all leaf nodes (which should be pretty easy using TreeLoc and isLeaf). Unfortunately I can't for the life of me work out how to walk the tree to do this.
Edit: Sorry I don't think I was clear enough in my original question. To be clear I want to walk the tree in such a way that I have information about the Node available to me. Flatten, foldRight etc just allow me to operate on [Int] whereas I want to be able to operate on Tree[Int] (or TreeLoc[Int]).
Having a look to how find is implemented in scalaz, my suggestion is to implement something like:
implicit class FilterTreeLoc[A](treeLoc: TreeLoc[A]){
def filter(p: TreeLoc[A] => Boolean): Stream[TreeLoc[A]] =
Cobind[TreeLoc].cojoin(treeLoc).tree.flatten.filter(p)
}
It behaves like the find but it gives you back instead a Stream[TreeLoc[A]] instead of an Option[TreeLoc[A]].
You can use this as tree.loc.filter(_.isLeaf) and tree.loc.filter(_.getLabel == 3).
Note: the use of an implicit class can be obviously avoided if you prefer to have this declared as a method instead.

Possible to make use of Scala's Option flatMap method more concise?

I'm admittedly very new to Scala, and I'm having trouble with the syntactical sugar I see in many Scala examples.
It often results in a very concise statement, but honestly so far (for me) a bit unreadable.
So I wish to take a typical use of the Option class, safe-dereferencing, as a good place to start for understanding, for example, the use of the underscore in a particular example I've seen.
I found a really nice article showing examples of the use of Option to avoid the case of null.
https://medium.com/#sinisalouc/demystifying-the-monad-in-scala-cc716bb6f534#.fhrljf7nl
He describes a use as so:
trait User {
val child: Option[User]
}
By the way, you can also write those functions as in-place lambda
functions instead of defining them a priori. Then the code becomes
this:
val result = UserService.loadUser("mike")
.flatMap(user => user.child)
.flatMap(user => user.child)
That looks great! Maybe not as concise as one can do in groovy, but not bad.
So I thought I'd try to apply it to a case I am trying to solve.
I have a type Person where the existence of a Person is optional, but if we have a person, his attributes are guaranteed. For that reason, there are no use of the Option type within the Person type itself.
The Person has an PID which is of type Id. The Id type consists of two String types; the Id-Type and the Id-Value.
I've used the Scala console to test the following:
class Id(val idCode : String, val idVal : String)
class Person(val pid : Id, val name : String)
val anId: Id = new Id("Passport_number", "12345")
val person: Person = new Person(anId, "Sean")
val operson : Option[Person] = Some(person)
OK. That setup my person and it's optional instance.
I learned from the above linked article that I could get the Persons Id-Val by using flatMap; Like this:
val result = operson.flatMap(person => Some(person.pid)).flatMap(pid => Some(pid.idVal)).getOrElse("NoValue")
Great! That works. And if I infact have no person, my result is "NoValue".
I used flatMap (and not Map) because, unless I misunderstand (and my tests with Map were incorrect) if I use Map I have to provide an alternate or default Person instance. That I didn't want to have to do.
OK, so, flatMap is the way to go.
However, that is really not a very concise statement.
If I were writing that in more of a groovy style, I guess i'd be able to do something like this:
val result = person?.pid.idVal
Wow, that's a bit nicer!
Surely Scala has a means to provide something at least nearly as nice as Groovy?
In the above linked example, he was able to make his statement more concise using some of that syntactical sugar I mentioned before. The underscore:
or even more concise:
val result = UserService.loadUser("mike")
.flatMap(_.child)
.flatMap(_.child)
So, it seems in this case the underscore character allows you to skip specifying the type (as the type is inferred) and replace it with underscore.
However, when I try the same thing with my example:
val result = operson.flatMap(Some(_.pid)).flatMap(Some(_.idVal)).getOrElse("NoValue")
Scala complains.
<console>:15: error: missing parameter type for expanded function ((x$2) => x$2.idVal)
val result = operson.flatMap(Some(_.pid)).flatMap(Some(_.idVal)).getOrElse("NoValue")
Can someone help me along here?
How am I misunderstanding this?
Is there a short-hand method of writing my above lengthy statement?
Is flatMap the best way to achieve what I am after? Or is there a better more concise and/or readable way to do it ?
thanks in advance!
Why do you insist on using flatMap? I'd just use map for your example instead:
val result = operson.map(_.pid).map(_.idVal).getOrElse("NoValue")
or even shorter:
val result = operson.map(_.pid.idVal).getOrElse("NoValue")
You should only use flatMap with functions that return Options. Your pid and idVals are not Options, so just map them instead.
You said
I have a type Person where the existence of a Person is optional, but if we have a person, his attributes are guaranteed. For that reason, there are no use of the Option type within the Person type itself.
This is the essential difference between your example and the User example. In the User example, both the existence of a User instance, and its child field are options. This is why, to get a child, you need to flatMap. However, since in your example, only the existence of a Person is not guaranteed, after you've retrieved an Option[Person], you can safely map to any of its fields.
Think of flatMap as a map, followed by a flatten (hence its name). If I mapped on child:
val ouser = Some(new User())
val child: Option[Option[User]] = ouser.map(_.child)
I would end up with an Option[Option[User]]. I need to flatten that to a single Option level, that's why I use flatMap in the first place.
If you looking for the most concise solution, consider this:
val result = operson.fold("NoValue")(_.pid.idVal)
Though one could find it not clear or confusing

Idiomatic syntax for Option when the meaningful value is None

This is purely a coding-style question.
A function I'm calling returns an Option, and I want to take a specific action if it's equal to None.
Say, for example, that I'm trying to create a default user at boot time if it doesn't already exist. I'd call a function that attempts to find a user that matches the default one, and returns an Option[User].
If that return value is None, I'd like to run some user creation code. If not, I'm done.
I'm wondering what's the most idiomatic Scala syntax for this. What I have so far is:
def getUser(name: String): Option[User] = ...
getUser("admin") getOrElse createUser("admin", "ChangeThisNow!")
getUser("admin") match {
case None => createUser("admin", "ChangeThisNow!")
case _ =>
}
if(getUser("admin") == None) createUser("admin", "ChangeThisNow!")
The first solution seems like the most functional one, but I can't help but feel that there might be better ones - possibly by using partially applied functions, which I admit I'm still a bit fuzzy about.
Since in your case the goal is to cause a side effect, I'd use a conditional to stress that, instead of using getOrElse.
if (getUser("admin").isEmpty)
createUser("admin", "ChangeThisNow!")
Remember that scala is a multi-paradigm language.
In addition to syntax, you want to consider concepts such as cohesion (single responsibility) and so you can consider the composition of your objects in addition to the actual idioms you use in the syntax.
The OO way might be to decorate the object/class that getUser belongs to in to put that concern of creating the user in a wrapper so that other code that calls the getUser function never has to deal with that concern. This fits nicely with open/closed principle and single responsibility. This is a bit of an anemic domain model anti-pattern here but may show how OO can be used to extend the conversation into actual design.
Either pattern matching or getOrElse are reasonable solutions. Generally if statements aren't used against Monads like the option - at least not that I see.
Either way, I beleive the expression should return the result even if there are side effects (user creation).
case class User(name: String)
class UserService {
def getUser(name: String): Option[User] = ???
def createUser(name: String): User = ???
}
class UserServiceDecorator extends UserService {
override def getUser(name: String): Option[User] =
Some(super.getUser(name).getOrElse(super.createUser(name)))
}
Really the best way to do this is to assign the result to a meaningful variable name so your future code doesn't need to know if createUser was called or not.
val user = getUser("admin").getOrElse(createUser("admin", "ChangeThisNow!"))
This way you can use the user variable regardless of if you've created a new user or not.

Is this a good return-type pattern for designing Scala API's?

I see this type of pattern (found this example here) quite often in Scala:
class UserActor extends Actor {
def receive = {
case GetUser(id) =>
// load the user, reply with None or Some(user)
val user: Option[User] = ...
sender ! user
case FindAll() =>
// find all users
val users: List[User] = ...
sender ! users
case Save(user) =>
// persist the user
sender ! Right(user)
}
}
So depending on the call you get: Option[User], List[User], Right[User]. This approach is fine! I'm just asking out of interest if this is optimal? For example (and this may be a bad one): Will it make API's better or worse to try and generalise by always returning List[User]? So when a user is not found or if a save fails, then the list will simply be empty. I'm just curious.... any other suggestions on how the above 'pattern' may be improved?
I'm just trying to identify a perfect pattern for this style of API where you sometimes get one entity and sometimes none and sometimes a list of them. Is there a 'best' way to do this, or does everyone role their own?
The return types should help clarify your API's intended behavior.
If GetUser returned a List, developers might get confused and wonder if multiple users could possibly be returned. When they see that an Option is returned, they will immediately understand the intended behavior.
I once had to work with a fairly complex API which provided CRUD operations that had been generalized in the manner you describe. I found it to be difficult to understand, vaguely defined, and hard to work with.
In my opinion it is a very good pattern for API design.
I use very often Option as return type of my functions, if I want to return a single element, obviously because I don't need to deal with null. Returning a Seq is naturally for multiple elements and Either is optimal if you want to return a failure-description, I use it often while parsing I/O. Sometimes I even combine the Seq with one of the others. You likely don't know the preferences and goals of an user of your API, so it makes sence to provide all of these return-types to make the user feel as comfortable as possible.