how do you destructure a list in scala - scala

I have this code:
val host:String = Play.configuration.getString("auth.ldap.directory.host").get
val port:java.lang.Integer = Play.configuration.getString("auth.ldap.directory.port").get.toInt
val userDNFormat:String = Play.configuration.getString("auth.ldap.userDNFormat").get
to which I need to add a dozen more config options, so I was hoping to refactor it to something like:
val params = Seq("auth.ldap.directory.host", "auth.ldap.directory.port", "auth.ldap.userDNFormat")
params.map(Play.configuration.getString) match {
case host~port~userDNFormat => foo(host, port, userDNFormat)
}
I made that code up. What is the proper syntax to do this? On the map/match line I get this error, which I do not understand:
error: type mismatch;
found : (String, Option[Set[String]]) => Option[String]
required: java.lang.String => ?

in order to match on a sequence, you can write
case Seq(host, port, userDNFormat) => foo(host, port, userDNFormat)

Related

Distinguish union type with type parameter in Scala 3

In Scala 3, given such a type alias:
type Test[A] = A | Option[A]
val first: Test[String] = "gandalf"
val second: Test[String] = None
val third: Test[String] = Some("sam")
how can i distinguish which one of the two cases I have (A or Option[A])?
When trying to write code, I think the main problem is that for the compiler and type, including Either[String, B], matches A`. I don't even know if there is an idiomatic solution for my problem.
This is my best attemp, any one other failed:
def get[A](input: Test[A]): A =
input match
case Some(value) => value.asInstanceOf[A]
case None => throw new RuntimeException("Error!")
case _ => input.asInstanceOf[A]
get(first) // "gandalf"
get(second) // Exception!!!
get(third) // sam"
as you can see value is not recognized to be the same type as the type parameter A and the A case at the bottom can't really be checked at runtime (trying case a: A => gives a compilation error) so I catch it by exclusion from the other two. This doesn't look like an optimal solution.

Scala Nested HashMaps, how to access Case Class value properties?

New to Scala, continue to struggle with Option related code. I have a HashMap built of Case Class instances that themselves contain hash maps with Case Class instance values. It is not clear to me how to access properties of the retrieved Class instances:
import collection.mutable.HashMap
case class InnerClass(name: String, age: Int)
case class OuterClass(name: String, nestedMap: HashMap[String, InnerClass])
// Load some data...hash maps are mutable
val innerMap = new HashMap[String, InnerClass]()
innerMap += ("aaa" -> InnerClass("xyz", 0))
val outerMap = new HashMap[String, OuterClass]()
outerMap += ("AAA" -> OuterClass("XYZ", innerMap))
// Try to retrieve data
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap
This produces error: value nestedMap is not a member of Option[ScalaFiddle.OuterClass]
// Try to retrieve data a different way
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap
This produces error: value nestedMap is not a member of Product with Serializable
Please advise on how I would go about getting access to outerMapTest.nestedMap. I'll eventually need to get values and properties out of the nestedMap HashMap as well.
Since you are using .getOrElse("someKey", None) which returns you a type Product (not the actual type as you expect to be OuterClass)
scala> val outerMapTest = outerMap.getOrElse("AAA", None)
outerMapTest: Product with Serializable = OuterClass(XYZ,Map(aaa -> InnerClass(xyz,0)))
so Product either needs to be pattern matched or casted to OuterClass
pattern match example
scala> outerMapTest match { case x : OuterClass => println(x.nestedMap); case _ => println("is not outerclass") }
Map(aaa -> InnerClass(xyz,0))
Casting example which is a terrible idea when outerMapTest is None, (pattern matching is favored over casting)
scala> outerMapTest.asInstanceOf[OuterClass].nestedMap
res30: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))
But better way of solving it would simply use .get which very smart and gives you Option[OuterClass],
scala> outerMap.get("AAA").map(outerClass => outerClass.nestedMap)
res27: Option[scala.collection.mutable.HashMap[String,InnerClass]] = Some(Map(aaa -> InnerClass(xyz,0)))
For key that does not exist, gives you None
scala> outerMap.get("I dont exist").map(outerClass => outerClass.nestedMap)
res28: Option[scala.collection.mutable.HashMap[String,InnerClass]] = None
Here are some steps you can take to get deep inside a nested structure like this.
outerMap.lift("AAA") // Option[OuterClass]
.map(_.nestedMap) // Option[HashMap[String,InnerClass]]
.flatMap(_.lift("aaa")) // Option[InnerClass]
.map(_.name) // Option[String]
.getOrElse("no name") // String
Notice that if either of the inner or outer maps doesn't have the specified key ("aaa" or "AAA" respectively) then the whole thing will safely result in the default string ("no name").
A HashMap will return None if a key is not found so it is unnecessary to do getOrElse to return None if the key is not found.
A simple solution to your problem would be to use get only as below
Change your first get as
val outerMapTest = outerMap.get("AAA").get
you can check the output as
println(outerMapTest.name)
println(outerMapTest.nestedMap)
And change the second get as
val nestedMap = outerMapTest.nestedMap.get("aaa").get
You can test the outputs as
println(nestedMap.name)
println(nestedMap.age)
Hope this is helpful
You want
val maybeInner = outerMap.get("AAA").flatMap(_.nestedMap.get("aaa"))
val maybeName = maybeInner.map(_.name)
Which if your feeling adventurous you can get with
val name: String = maybeName.get
But that will throw an error if its not there. If its a None
you can access the nestMap using below expression.
scala> outerMap.get("AAA").map(_.nestedMap).getOrElse(HashMap())
res5: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))
if "AAA" didnt exist in the outerMap Map object then the below expression would have returned an empty HashMap as indicated in the .getOrElse method argument (HashMap()).

Type Mismatch in scala case match

Trying to create multiple dataframes in a single foreach, using spark, as below
I get values delivery and click out of row.getAs("type"), when I try to print them.
val check = eachrec.foreach(recrd => recrd.map(row => {
row.getAs("type") match {
case "delivery" => val delivery_data = delivery(row.get(0).toString,row.get(1).toString)
case "click" => val click_data = delivery(row.get(0).toString,row.get(1).toString)
case _ => "not sure if this impacts"
}})
)
but getting below error:
Error:(41, 14) type mismatch; found : String("delivery") required: Nothing
case "delivery" => val delivery_data = delivery(row.get(0).toString,row.get(1).toString)
^
My plan is to create dataframe using todf() once I create these individual delivery objects referenced by delivery_data and click_data by:
delivery_data.toDF() and click_data.toDF().
Please provide any clue regarding the error above (in match case).
How can I create two df's using todf() in val check?
val declarations make your first 2 cases return type to be unit, but in the third case you return a String
for instance, here the z type was inferred by the compiler, Unit:
def x = {
val z: Unit = 3 match {
case 2 => val a = 2
case _ => val b = 3
}
}
I think you need to cast this match clause to String.
row.getAs("type").toString

How to reassign value to def in scala

I am writing a parser in which I have the following function:
def lastop:(Either[RDD[(Int,Array[Float])], Float], Either[RDD[(Int,Array[Float])], Float]) => RDD[(Int,Array[Float])] = add
In which "add" is a function to perform addition. Then I want to use it in my program like the following line:
terms.foreach(t =>
t match { case nums ~ op => lastop = op; stack = reduce(stack ++ nums, op)}
I am getting the following error:
[error] /home/mahsa/calculator/temp/ScalaParser.scala:183: reassignment to val
[error] t match { case nums ~ op => lastop = op; stack = reduce(stack ++ nums, op)}
[error] ^
Can't figure how to solve this error!
You want to store a changing reference to the function you want to invoke. If you are storing and reassigning something, that implies you need a var, not a val or a def. Try declaring lastop like:
var lastop:(Either[RDD[(Int,Array[Float])], Float], Either[RDD[(Int,Array[Float])], Float]) => RDD[(Int,Array[Float])] = add
Note that you will still need to invoke lastop like a function, since retrieving the var's value will return a function. It's a subtle but significant difference.

Scala Macros: How to create setter function for case classes

I would like to use macro to generate a setter for case classes. e.g:
case class Person(name: String, age: Int)
Macro.mkSetter[Person, String]("name") : Person => String => Person
I tried the following implementation but I keep getting the following
error: scala: Error: Unknown source file: embeddedFile--QuasiquoteCompat.scala#6....
(I am using scala 2.10.3 with macro-paradise 2.0.0-SNAPSHOT)
object Macro {
def mkSetter[A, B](fieldName: String): (A,B) => A = macro mkSetter_impl[A,B]
def mkSetter_impl[A: c.WeakTypeTag, B: c.WeakTypeTag](c : Context)(fieldName: c.Expr[String]): c.Expr[(A,B) => A] = {
import c.universe._
val (aTpe, bTpe) = (weakTypeOf[A], weakTypeOf[B])
val constructor = aTpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.getOrElse(c.abort(c.enclosingPosition, s"Cannot find constructor in ${weakTypeOf[A]}"))
val field = constructor.paramss.head.find(
_.name.decoded == fieldName.toString()
).getOrElse(c.abort(c.enclosingPosition, s"Cannot find constructor field named in $fieldName"))
c.Expr[(A,B) => A](q"{(a: $aTpe, b: $bTpe) => a.copy(${field.name} = b)}")
}
}
I do realise that _.name.decoded == fieldName.toString() is not correct way to check method name (even if _.name.decoded == "name" seems to be ok)
Bonus point: generalise macro with varags parameters for parameters with same type, e.g.
def mkSetter[A, B](fieldNames: String*): A => B => B ... => A = macro mkSetter_impl[A,B]
Thank you!
Seems to be caused by https://github.com/scalamacros/paradise/issues/11. This week I planned to fix that issue, so it should be fine soon. You could subscribe to updates at scalamacros.org (http://scalamacros.org/news/rss.xml) or follow me on Twitter to get notified when the fix is deployed.