I want to be able to have a method with an optional parameter. When that optional parameter is present, it will call a specific DB query that returns records filtered with the optional parameter. If that optional parameter isn't present, I want it to call a different DB query that doesn't filter by the optional parameter.
The first query is not written yet, but would have the same return structure and types. The second query is written, and works fine without the optional parameter and the cases.
def getRecords(id: String, type: String = ""): Future[List[Set[String]]] = {
case Some(type) =>
val query =>
s"""
| ...
""".stripMargin
case _ =>
val query =>
s"""
| ...
""".stripMargin
record = get(dbResult).asList.asScala.map(_.toString).toSet
}
The error I recieve is
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: scala.concurrent.Future[List[Set[String]]]
: Future[List[Set[String]]] = {
^
Can someone please explain to me what the error means? and also how to design my method to work the way I would like it to?
Note: Some of the details of the method have been omitted. It essentially just returns a record of the return type and whatever data was taken by one of the queries.
Re your comment, sure, here you go:
def getRecords(id: String, `type`: Option[String] = None): Future[List[Set[String]]] = {
val matchResult = `type` match {
case Some(t) => //t is your string
val query =
s"""
| ...
""".stripMargin
//do something with your query val
case _ =>
val query =
s"""
| ...
""".stripMargin
//do something with your query val
}
//use your matchResult here, whatever that ends up being
//not sure how this works but just copied from your question:
get(dbResult).asList.asScala.map(_.toString).toSet
}
Obviously you'll have to use query somewhere, but I assume you've just simplified that away. If you're worried about empty strings, you can add a guard to your first case clause: case Some(t) if t.nonEmpty => .... type is backticked because it's a keyword. If you use a non-keyword name you won't need the backticks.
Related
I have a method, which need String type as an argument:
type Identity = String
case class RequireSmth(param: Identity) extends Something
Now I call this method in more complex order:
createMe(as[List])(arg =>{ parse(RequireSmth(getAction(name, surname).map(bool => getData(surname, bool).id))) })
Parse looks like:
def parse(ob: Something)
Where:
def getAction(name: String, surname: String): Future[Boolean] = {
someObject.get(name).map(_.getSomething(surname).isPossibleToTake.getOrElse(false)) //someObject is defined in constructor and does not matter here
}
def getData: (String, Boolean) => MyObject = {
case ("Doe", true) => possible
case _ => notPossible
}
MyObject, possible and notPossible definition:
case class MyObject(id : String, name: String, surname: String)
val possible = MyObject( id = "ok", name ="John", surname = "Doe")
val notPossible = MyObject( id = "not ok", name ="John", surname = "Doe")
The problem is, when I call RequireSmth method I got an error:
type mismatch;
found: scala.concurrent.Future[String]
required: com.my.smth.Identity (which expands to) String
How can I solve this problem to return Identity (or String) instead of Future[String]?
Keep the information inside the Future like this:
getAction(name, surname).map(bool => getData(surname, bool).id).map(RequireSmth)
Just keep chaining the operations together, keeping everything inside the Future:
getAction(name, surname)
.map(bool => getData(surname, bool).id)
.map(RequireSmth) // Or x => RequireSmth(x) if necessary
.map(parse)
At some point you will get to a method that has a side-effect and returns Unit, and that will be executed when all the actions in the Future are complete.
In the unlikely event that you actually need to get the value out of the Future, use Await.result. But in most cases this will not be necessary.
You need to flip the method calls:
val res: Future[???] =
getAction(name, surname)
.map(bool => getData(surname, bool).id)
.map(RequireSmth)
.map(parse)
Note that Future[String] is not a String, it's a computation that will yield a value in the future, and that means that the entire computation stack needs to return a Future[T] as well (unless you explicitly await, which blocks and is not recommended).
I am playing around with some Scala code and have met with an error message I don't quite follow. Below is my code
val ignoredIds = Array("one", "two", "three")
def csNotify(x : Any): String = {
case org: String if !ignoredIds.contains(x) =>
println( s" $x should not be here")
"one"
case org : String if ignoredIds.contains(x) =>
println(s"$x should be here")
"two"
}
csNotify("four")
The console output is that I am the arguments for a default function must be known. The error point appears to be pointing at the " String = ". Why would this be the case ? The function should check the two cases and return a string ?
Your case is not finding the match against which it can check your block , and you have missed the match block:
val ignoredIds = Array("one", "two", "three")
def csNotify(x : Any): String = x match {
case org: String if !ignoredIds.contains(x) =>
println( s" $x should not be here")
"one"
case org : String if ignoredIds.contains(x) =>
println(s"$x should be here")
"two"
}
csNotify("four")
So basically when you pass x in method , you have to give it for match as well.
Amit Prasad's answer already shows how to fix it, but to explain the error message:
{
case org: String if !ignoredIds.contains(x) =>
println( s" $x should not be here")
"one"
case org : String if ignoredIds.contains(x) =>
println(s"$x should be here")
"two"
}
on its own (without ... match before it) is a pattern-matching anonymous function, which can only be used where the compiler knows the argument type from the context, i.e. the expected type must be either PartialFunction[Something, SomethingElse] or a single-abstract-method type (including Something => SomethingElse).
Here the expected type is String, which isn't either of those, so the compiler complains about not knowing what the argument type is.
You need to use match keyword here to use cases. There might be some value for which you will be using pattern matching. So use the following code in your function:
x match {
case org: String if !ignoredIds.contains(x) => ???
case org : String if ignoredIds.contains(x) => ???
}
Also, you should consider adding one more case which is default. As you know the parameter x of your function def csNotify(x: Any): String is of type any. So anything other than String can also be passed here like Int or Boolean or any custom type. In that case, the code will break with match error.
There will also be a compiler warning saying match is not exhaustive as the current code does not handle all possible values for type Any of parameter x.
But if you add one default case in your pattern matching, all the cases which are not handled by the first two cases (unexpected type or values) will go to the default case. In this way the code will be more robust:
def csNotify(x : Any): String = x match {
case org: String if !ignoredIds.contains(org) => ???
case org : String if ignoredIds.contains(org) => ???
case org => s"unwanted value: $org" // or any default value
}
Note: Kindly replace ??? with your intended code. :)
I have a simple Scops parser that looks like
val parser: scopt.OptionParser[Config] = new scopt.OptionParser[Config]("my-app") {
head("scopt", "3.x")
(...)
opt[String]('q', "query")
.text("The query.")
.action { (value, conf) => conf.copy(
query = value
)}
.optional
}
(...)
parser.parse(args, Config()) match {
case Some(config) => drive(config)
(...)
In my driver function I want to initialize a parameter with what the user provided via the argument or some default value otherwise.
I could do something like
var myQuery = _
if config.query != "" myQuery = config.query
else myQuery = config.query
But, (i) I doubt that testing against the empty string is the right way to check if the user provided an optional argument or not and (ii) that doesn't look like a very functional to write this in Scala.
Question: Is there a nice functional way to do this? I considered pattern matching like below but the Scopt arguments do not seem to be returned as Option[String]
val myQuery: String = config.query match {
case Some(q) => q
case None => "This is the default query"
}
Just make Config#query an Option[String] (with None as default) and change the query = value line to query = Some(value).
I need return tuple , but if something goes wrong I want return empty tuple, like Seq.empty[Type] or Nil in Lists. Is it possible?
Also I am curious about is it possible with String type.
I want return empty tuple
That doesn't make sense. A tuple is not a collection. The idea of "emptiness" is simply non-sensical. The length of a tuple is part of its type. So, an empty tuple is a different type than a non-empty tuple.
In fact, it doesn't even make sense to talk about "tuple" as a type. There are pairs (2-tuples aka Tuple2), triples (3-tuples aka Tuple3), quadruples, quintuples, sixtuples, septuples, octuples, 9-tuples, 10-tuples, etc, and they are all different types.
Also, more or less the only sensible thing you can do with a tuple is to extract its elements. So, for a tuple with no elements, there is pretty much no sensible thing you can do. What use is a structure that holds no values and has no operations? It's completely useless.
In fact, a 0-tuple is isomorphic to the Unit value, the value which denotes the absence of a useful value. In Scala, and also Haskell, the syntax for an empty tuple is actually used for denoting the Unit value:
val u = ()
// => u: Unit = ()
Also I am curious about is it possible with String type.
Yes, of course, you can have an empty string:
val s = ""
// => s: String = ""
Since you need to return an a value that can go wrong. In Scala the recommended way to deal with this is returning an Option, Try or Either value.
For instance:
def somethingThatCanGoWrongWithTry(): Try[(Int, String)] = {
Try{
val intValue = sideEffectValueInt()
val stringValue = sideEffectValueString()
(intValue, stringValue)
}
}
def somethingThatCanGoWrongWithOption(): Option[(Int,String)] = {
Try {
val intValue = sideEffectValueInt()
val stringValue = sideEffectValueString()
(intValue, stringValue)
}.toOption
}
def somethingThatCanGoWrongWithEither(): Either[Oops, (Int,String)] = {
Try {
val intValue = sideEffectValueInt()
val stringValue = sideEffectValueString()
(intValue, stringValue)
} match {
case Success(value) => Right(value)
case Failure(exception) => Left(Oops(exception))
}
}
I'm new to Scala and I'm trying to convert code of the form
val series: ListBuffer[Seq[Seq[Any]]] = ListBuffer[Seq[Seq[Any]]]()
points.foreach(point => {
if( conditionA )
series += doA(...) // returns a ListBuffer[Seq[Any]]
else
series += doB(...) // returns a ListBuffer[Seq[Any]]
})
to use .map(). I'm thinking its something like:
val series: ListBuffer[Seq[Seq[Any]]] = points.map(point => {
case conditionA => doA(...)
case _ => doB(...)
})
but this doesn't compile because (I believe) the mapped sequences get appended as a single Seq[Any] instead of Seq[Seq[Any]], so I get the error
Expression of type Seq[Any] doesn't conform to expected type ListBuffer[Seq[Seq[Any]]]
Any ideas? Is there something wrong with syntax?
Let me suppose a few things, you have some function def doA(arg1: A): ListBuffer[Seq[Any]] such that you ultimately want to arrive at a List[Seq[Any]] as the final result type after mapping this function over your collection. Then what you want is flatMap instead of map:
val series = points flatMap{
case point if conditionA(point) => doA(point) result ()
case point => doB(point) result ()
}
The reason I make such a supposition is that the only reason you'd ever want to use a ListBuffer[A] in the general form is to create a List[A] through some side-effecting expression. Hence, you ultimately want a List[Seq[A]] as your final output.