Scala - How to safely operate on a map element - scala

I want to get an element from a mutable map and do an operation on it.
For example I want to change his name value (the element on the map will be with the new value)
and I want to return it in the end
to start I wrote a working code but it is very Java
var newAppKey: AppKey = null
val appKey = myMap(request.appKeyId)
if (appKey != null) {
newAppKey = appKey.copy(name = request.appKeyName)
myMap.put(appKey.name, newAppKey)
newAppKey
} else {
newAppKey = null
}
This code works but it very java.
I though about something like
val newAppKey = appIdToApp(request.appKeyId) match {
case: Some(appKey) => appKey.copy(name = request.appKeyName)
case: None => None{AppKey}
}
Which doesn't compile or updates the myMap object with the new value.
How do I improve it to scala concepts.

Simply:
val key = request.appKeyId
val newValueOpt = myMap.get(key).map(_.copy(name = request.appKeyName))
newValueOpt.foreach(myMap.update(key, _))

There are a couple of mistakes in your code.
case: Some(appKey) => appKey.copy(name = request.appKeyName)
This syntax for case is incorrect. It should be
case Some(appKey) => appKey.copy(name = request.appKeyName)
Also, the return type of your expression is currently Any (Scala equivalent of Object), because your success case returns an object of type (appKey's type) whereas the failure case returns a None, which is of type Option. To make things consistent, your success case should return
Some(appKey.copy(name = request.appKeyName))
While there are better ways to deal with Options than pattern matching, the corrected code would be
val newAppKey = appIdToApp(request.appKeyId) map (appKey =>
appKey.copy(name = request.appKeyName))

Related

unable to convert a java.util.List into Scala list

I want that the if block returns Right(List[PracticeQuestionTags]) but I am not able to do so. The if/else returns Either
//I get java.util.List[Result]
val resultList:java.util.List[Result] = transaction.scan(scan);
if(resultList.isEmpty == false){
val listIterator = resultList.listIterator()
val finalList:List[PracticeQuestionTag] = List()
//this returns Unit. How do I make it return List[PracticeQuestionTags]
val answer = while(listIterator.hasNext){
val result = listIterator.next()
val convertedResult:PracticeQuestionTag = rowToModel(result) //rowToModel takes Result and converts it into PracticeQuestionTag
finalList ++ List(convertedResult) //Add to List. I assumed that the while will return List[PracticeQuestionTag] because it is the last statement of the block but the while returns Unit
}
Right(answer) //answer is Unit, The block is returning Right[Nothing,Unit] :(
} else {Left(Error)}
Change the java.util.List list to a Scala List as soon as possible. Then you can handle it in Scala fashion.
import scala.jdk.CollectionConverters._
val resultList = transaction.scan(scan).asScala.toList
Either.cond( resultList.nonEmpty
, resultList.map(rowToModel(_))
, new Error)
Your finalList: List[PracticeQuestionTag] = List() is immutable scala list. So you can not change it, meaning there is no way to add, remove or do change to this list.
One way to achieve this is by using scala functional approach. Another is using a mutable list, then adding to that and that list can be final value of if expression.
Also, a while expression always evaluates to Unit, it will never have any value. You can use while to create your answer and then return it seperately.
val resultList: java.util.List[Result] = transaction.scan(scan)
if (resultList.isEmpty) {
Left(Error)
}
else {
val listIterator = resultList.listIterator()
val listBuffer: scala.collection.mutable.ListBuffer[PracticeQuestionTag] =
scala.collection.mutable.ListBuffer()
while (listIterator.hasNext) {
val result = listIterator.next()
val convertedResult: PracticeQuestionTag = rowToModel(result)
listBuffer.append(convertedResult)
}
Right(listBuffer.toList)
}

Scala: Create object only if it doesn't exist yet

I'm new to Scala, and this probably a very simple question, but I'm struggling to figure out how to make an object only if one doesn't exist yet.
I would like to query a database, and find out if there's anything present, if so, store it in an object, otherwise create a new one. In Java I know that this would be something like
PushMessage push = null;
if(GetFromDatabase() == null) {
push = new PushMessaage(param1, param2...);
}
else {
push = GetFromDatabase();
}
But, how do I do this in Scala. When I try and do the same thing, it tells me that GetFromDatabase() doesn't conform to expected type Null. Similarly, I tried doing pattern matching and doing something like
val push = GetFromDatabase match {
case Some(pushMessage) => pushMessage
case None => new PushMessage(param1, param2...)
}
But, that also didn't work as it told me that
Constructor cannot be instantiated to expected type, found: Some[A], expected: PushMessage
So, how do I do this? Any and all help would be really appreciated.
I assume your GetFromDatabase returns either null or PushMessage, so in order to pattern match correctly, you need to wrap it into Option:
val push = Option(GetFromDatabase) match {
case Some(pushMessage) => pushMessage
case None => new PushMessage(param1, param2...)
}
Or (bad style, but gives an understanding of how it works):
// Option(null) === None, Option(notNull) === Some(notNull):
// same as `if (x ne null) Some(x) else None
val pushMaybe: Option[PushMessage] = Option(GetFromDatabase)
val push: PushMessage =
if (pushMaybe.isEmpty) new PushMessage(param1, param2...)
else pushMaybe.get
You can simplify it all with:
val push = Option(GetFromDatabase).getOrElse(new PushMessage(param1, param2...))
P.S. If GetFromDatabase isn't some external method, it's better to rewrite it as returning Option[PushMessage] instead of PushMessage, something like:
def getFromDatabase = {
val rs = driver.getResulSet(query)
if (!rs.isBeforeFirst()) None else Some(parse(rs))
}
Here's a little demonstration why "cool" things are not always cool. Let's see Scala generated code for two cases (I made them very simple):
def getMessage: String = null
val m = getMessage
val push = if (m == null) new AnyRef else m
=>
iw.this.m = iw.this.getMessage();
iw.this.push = if (iw.this.m().==(null))
new Object()
else
iw.this.m();
vs
def getMessage: String = null
val push = Option(getMessage) match {
case Some(x) => x
case None => new AnyRef
}
=>
iw.this.push = {
case <synthetic> val x1: Option = scala.Option.apply(iw.this.getMessage());
case6(){
if (x1.$isInstanceOf[Some]())
{
<synthetic> val x2: Some = (x1.$asInstanceOf[Some](): Some);
{
val x: String = x2.x().$asInstanceOf[String]();
matchEnd5(x)
}
}
else
case7()
};
case7(){
if (scala.None.==(x1))
matchEnd5(new Object())
else
case8()
};
case8(){
matchEnd5(throw new MatchError(x1))
};
matchEnd5(x: Object){
x
}
};
So as long as we are not propagating null (and we don't) I don't see any advantages of the second option.
UPDATE
As requested:
val path = Option(m).getOrElse(new AnyRef)
=>
final <artifact> private[this] def $anonfun$1(): Object = new Object();
...
iw.this.path = scala.Option.apply($line13.iw.m()).getOrElse({
(() => iw.this.$anonfun$1())
});
I wouldn't consider it much better than the second option above. getOrElse hides about the same logic, and we have anonymous function since getOrElse takes by-name argument.
In fact it's not just about saving cycles. Constructing and deconstructing Option object for the sake of avoiding local null? Or saving one line? I would totally accept it if we used Option for passing it further.

Cleanest way in Scala to avoid nested ifs when transforming collections and checking for error conditions in each step

I have some code for validating ip addresses that looks like the following:
sealed abstract class Result
case object Valid extends Result
case class Malformatted(val invalid: Iterable[IpConfig]) extends Result
case class Duplicates(val dups: Iterable[Inet4Address]) extends Result
case class Unavailable(val taken: Iterable[Inet4Address]) extends Result
def result(ipConfigs: Iterable[IpConfig]): Result = {
val invalidIpConfigs: Iterable[IpConfig] =
ipConfigs.filterNot(ipConfig => {
(isValidIpv4(ipConfig.address)
&& isValidIpv4(ipConfig.gateway))
})
if (!invalidIpConfigs.isEmpty) {
Malformatted(invalidIpConfigs)
} else {
val ipv4it: Iterable[Inet4Address] = ipConfigs.map { ipConfig =>
InetAddress.getByName(ipConfig.address).asInstanceOf[Inet4Address]
}
val dups = ipv4it.groupBy(identity).filter(_._2.size != 1).keys
if (!dups.isEmpty) {
Duplicates(dups)
} else {
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
val taken: Iterable[Inet4Address] = ipAvailability.filter(!_._2).keys
if (!taken.isEmpty) {
Unavailable(taken)
} else {
Valid
}
}
}
}
I don't like the nested ifs because it makes the code less readable. Is there a nice way to linearize this code? In java, I might use return statements, but this is discouraged in scala.
I personally advocate using a match everywhere you can, as it in my opinion usually makes code very readable
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil =>
val ipv4it = ipConfigs.map { ipc =>
InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address]
}
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil =>
val taken = ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys
if (taken.nonEmpty) Unavailable(taken) else Valid
case dups => Duplicates(dups)
}
case invalid => Malformatted(invalid)
}
Note that I've chosen to match on the else part first, since you generally go from specific to generic in matches, since Nil is a subclass of Iterable I put that as the first case, eliminating the need for an i if i.nonEmpty in the other case, since it would be a given if it didn't match Nil
Also a thing to note here, all your vals don't need the type explicitly defined, it significantly declutters the code if you write something like
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
as simply
val ipAvailability = ipv4it.map(ip => (ip, isIpAvailable(ip)))
I've also taken the liberty of removing many one-off variables I didn't find remotely necessary, as all they did was add more lines to the code
A thing to note here about using match over nested ifs, is that is that it's easier to add a new case than it is to add a new else if 99% of the time, thereby making it more modular, and modularity is always a good thing.
Alternatively, as suggested by Nathaniel Ford, you can break it up into several smaller methods, in which case the above code would look like so:
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil => wellFormatted(ipConfigs)
case i => Malformatted(i)
}
def wellFormatted(ipConfigs: Iterable[IpConfig]): Result = {
val ipv4it = ipConfigs.map(ipc => InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address])
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil => noDuplicates(ipv4it)
case dups => Duplicates(dups)
}
}
def noDuplicates(ipv4it: Iterable[IpConfig]): Result =
ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys match {
case Nil => Valid
case taken => Unavailable(taken)
}
This has the benefit of splitting it up into smaller more manageable chunks, while keeping to the FP ideal of having functions that only do one thing, but do that one thing well, rather than having god-methods that do everything.
Which style you prefer, of course is up to you.
This has some time now but I will add my 2 cents. The proper way to handle this is with Either. You can create a method like:
def checkErrors[T](errorList: Iterable[T], onError: Result) : Either[Result, Unit] = if(errorList.isEmpty) Right() else Left(onError)
so you can use for comprehension syntax
val invalidIpConfigs = getFormatErrors(ipConfigs)
val result = for {
_ <- checkErrors(invalidIpConfigs, Malformatted(invalidIpConfigs))
dups = getDuplicates(ipConfigs)
_ <- checkErrors(dups, Duplicates(dups))
taken = getAvailability(ipConfigs)
_ <- checkErrors(taken, Unavailable(taken))
} yield Valid
If you don't want to return an Either use
result.fold(l => l, r => r)
In case of the check methods uses Futures (could be the case for getAvailability, for example), you can use cats library to be able of use it in a clean way: https://typelevel.org/cats/datatypes/eithert.html
I think it's pretty readable and I wouldn't try to improve it from there, except that !isEmpty equals to nonEmpty.

Scala: parsing an API parameter

My API currently take an optional parameter named gamedate. It is passed in as a string at which time I later parse it to a Date object using some utility code. The code looks like this:
val gdate:Option[String] = params.get("gamedate")
val res = gdate match {
case Some(s) => {
val date:Option[DateTime] = gdate map { MyDateTime.parseDate _ }
val dateOrDefault:DateTime = date.getOrElse((new DateTime).withTime(0, 0, 0, 0))
NBAScoreboard.findByDate(dateOrDefault)
}
case None => NBAScoreboard.getToday
}
This works just fine. Now what I'm trying to solve is I'm allowing multiple gamedates get passed in via a comma delimited list. Originally you can pass a parameter like this:
gamedate=20131211
now I want to allow that OR:
gamedate=20131211,20131212
That requires modifying the code above to try to split the comma delimited string and parse each value into a Date and change the interface to findByDate to accept a Seq[DateTime] vs just DateTime. I tried running something like this, but apparently it's not the way to go about it:
val res = gdates match {
case Some(s) => {
val dates:Option[Seq[DateTime]] = gdates map { _.split(",").distinct.map(MyDateTime.parseDate _ )}
val datesOrDefault:Seq[DateTime] = dates map { _.getOrElse((new DateTime).withTime(0, 0, 0, 0))}
NBAScoreboard.findByDates(datesOrDefault)
}
case None => NBAScoreboard.getToday
}
What's the best way to convert my first set of code to handle this use case? I'm probably fairly close in the second code example I provided, but I'm just not hitting it right.
You mixed up the containers. The map you call on dates unpackes the Option so the getOrElse is applied to a list.
val res = gdates match {
case Some(s) =>
val dates = gdates.map(_.split(",").distinct.map(MyDateTime.parseDate _ ))
val datesOrDefault = dates.getOrElse(Array((new DateTime).withTime(0, 0, 0, 0)))
NBAScoreboard.findByDates(datesOrDefault)
case _ =>
NBAScoreboard.getToday
}
This should work.

How to use scalax.io.CommandLineParser?

I want to create a class that takes string array as a constructor argument and has command line option values as members vals. Something like below, but I don't understand how the Bistate works.
import scalax.data._
import scalax.io.CommandLineParser
class TestCLI(arguments: Array[String]) extends CommandLineParser {
private val opt1Option = new Flag("p", "print") with AllowAll
private val opt2Option = new Flag("o", "out") with AllowAll
private val strOption = new StringOption("v", "value") with AllowAll
private val result = parse(arguments)
// true or false
val opt1 = result(opt1Option)
val opt2 = result(opt2Option)
val str = result(strOption)
}
Here are shorter alternatives to that pattern matching to get a boolean:
val opt1 = result(opt1Option).isInstanceOf[Positive[_]]
val opt2 = result(opt2Option).posValue.isDefined
The second one is probably better. The field posValue is an Option (there's negValue as well). The method isDefined from Option tells you whether it is a Some(x) or None.
I'm not personally familiar with Scalax or Bistate in particular, but just looking at the scaladocs, it looks like a left-right disjunction. Scala's main library has a monad very much like this (Either), so I'm surprised that they didn't just use the standard one.
In essence, Bistate and Either are a bit like Option, except their "None-equivalent" can contain a value. For example, if I were writing code using Either, I might do something like this:
def div(a: Int, b: Int) = if (b != 0) Left(a / b) else Right("Divide by zero")
div(4, 2) match {
case Left(x) => println("Result: " + x)
case Right(e) => Println("Error: " + e)
}
This would print "Result: 2". In this case, we're using Either to simulate an exception. We return an instance of Left which contains the value we want, unless that value cannot be computed for some reason, in which case we return an error message wrapped up inside an instance of Right.
So if I want to assign to variable boolean value of whether flag is found I have to do like below?
val opt1 = result(opt1Option) match {
case Positive(_) => true
case Negative(_) => false
}
Isn't there a way to write this common case with less code than that?