Create dynamic function name on the fly in Scala - scala

I have an object in which I have a bunch of implicit functions. I now want to have some implicits defined for several date formats: For example.,
val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
I want to go over this list and generate a function like this:
dateFormats foreach {
case dateFormat =>
implicit def ???: CsvFieldReader[DateTime] = (s: String) => Try {
DateTimeFormat.forPattern(dateFormat).parseDateTime(s)
}
}
How can I resolve the function name? I want the function name to be unique for each entry in the List!
Any ideas? Can I do this with macros?

If you create several implicits of the same type CsvFieldReader[DateTime] they will make ambiguity and implicits will not resolve.
Names of implicits don't matter (almost), their types do.

So, here is an implementation that works, even though it looks ugly!
implicit def dateTimeCSVConverter: CsvFieldReader[DateTime] = (s: String) => Try {
dateFormats.map {
case format => try {
Some(DateTimeFormat.forPattern(format).parseDateTime(s))
} catch {
case _: IllegalArgumentException =>
println(s"Date format $format incompatible, will try the next available format")
None
}
}.distinct.collectFirst {
case elem if elem.isDefined => elem.get
}.get
}

Related

Scala Error - Expression of type Unit doesn't conform to expected type File

I have the following code:
var tempLastFileCreated: File = try {
files(0)
} catch {
case e: ArrayIndexOutOfBoundsException => ???
}
where files is val files: Array[File] = dir.listFiles()
Now whatever I give in case e I get the message Expression of type Unit doesn't conform to expected type File
I understand that the right hand part of the => has to be something which is of type File.
Can anyone tell me what to put there?
You are promising that tempLastFileCreated is a File, therefore it cannot also be a Unit or a String, etc. You have a couple options. You could use a Option[File] instead:
val tempLastFileCreated: Option[File] = try {
Some(files(0))
}
catch {
case e: ArrayIndexOutOfBoundsException => None
}
Or if you wanted to store an error message, for example, another option is to use Either:
val tempLastFileCreated: Either[String, File] = try {
Right(files(0))
}
catch {
case e: ArrayIndexOutOfBoundsException => Left("index out of bounds!")
}
Whatever bests suits your needs. You might want to take a look at Scala's scala.util.Try data type, which is safer. For example,
val tempLastFileCreated: Option[File] = Try(files(0)) match {
case Success(file) => Some(file)
case Failure(throwable) => None //or whatever
}

How to write a custom decoder for [Option[Option[A]] in Circe?

I had written a Reads converter in play-json for Option[Option[A]] that had the following behavior:
//given this case class
case class MyModel(field: Option[Option[String]])
//this JSON -- maps to --> this MyModel:
//"{ \"field\": \"value\" }" --> MyModel(field = Some(Some("value")))
//"{ \"field\": null, ... }" --> MyModel(field = Some(None))
//"{ }" --> MyModel(field = None)
So, providing the value mapped to Some[Some[A]], providing null mapped to Some[None] (i.e. Some[Option.empty[A]]), and not providing the value mapped to just None (i.e. Option.empty[Option[A]]). Here's the play-json converter:
def readOptOpt[A](implicit r: Reads[A]): Reads[Option[Option[A]]] = {
Reads[Option[Option[A]]] { json =>
path.applyTillLast(json).fold(
identity,
_.fold(_ => JsSuccess(None), {
case JsNull => JsSuccess(Some(None))
case js => r.reads(js).repath(path).map(a => Some(Some(a)))
})
)
}
}
Now I am converting my play-json code to Circe, but I can't figure out how to write a Decoder[Option[Option[A]] that has the same behavior. That is, I need
def optOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]] = ??? //help!
Any ideas on how I can make this work? Thanks
I figured this out:
There were two problems:
1) How to deal with the case where the field was completely missing from the JSON. Turns out you have to use Decoder.reattempt in your custom decoder, following Circe's decodeOption code, which works.
2) How to have the compiler recognize cases of Option[Option[A]] when your decoder code is sitting in a helper object (or wherever). Turns out if you're using semi-auto derivation, you can create an implicit in the companion object and that will override the defaults:
//companion object
object MyModel {
implicit def myModelOptOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]]] =
MyHelperObject.optOptDecoder
implicit val myModelDecoder: Decoder[MyModel] = deriveDecoder
}
Anyway, I don't think this will be much help to anybody in the future, so unless I get any upvotes in the next few hours I think I'll just delete this.
Edit2: Okay it was answered so I won't delete it. Stay strong, esoteric circe question, stay strong...
An Option[Option[A]] is a bit odd. I understand and mostly agree with the reasoning, but I think it's weird enough that it may warrant just replacing it with your own class (and writing a decoder for that). Something like:
sealed trait OptionalNull[+A] {
def toOption: Option[Option[A]]
}
object NotPresent extends OptionalNull[Nothing] {
override def toOption = None
}
object PresentButNull extends OptionalNull[Nothing] {
override def toOption = Some(None)
}
case class PresentNotNull[A](value: A) extends OptionalNull[A] {
override def toOption = Some(Some(value))
}
This has the additional benefit of not having to worry about implicit precedence and stuff like that. Might simplify your decoder.
Here is another solution I found (This is not my gist):
sealed trait UpdateOrDelete[+A]
case object Delete extends UpdateOrDelete[Nothing]
final case class UpdateOptionalFieldWith[A](value: A) extends UpdateOrDelete[A]
object UpdateOrDelete {
implicit def optionalDecoder[A](implicit decodeA: Decoder[A]): Decoder[UpdateOptionalField[A]] =
Decoder.withReattempt {
// We're trying to decode a field but it's missing.
case c: FailedCursor if !c.incorrectFocus => Right(None)
case c =>
Decoder.decodeOption[A].tryDecode(c).map {
case Some(a) => Some(UpdateOptionalFieldWith(a))
case None => Some(Delete)
}
}
// Random UUID to _definitely_ avoid collisions
private[this] val marker: String = s"$$marker-${UUID.randomUUID()}-marker$$"
private[this] val markerJson: Json = Json.fromString(marker)
implicit def optionalEncoder[A](implicit encodeA: Encoder[A]): Encoder[UpdateOptionalField[A]] =
Encoder.instance {
case Some(Delete) => Json.Null
case Some(UpdateOptionalFieldWith(a)) => encodeA(a)
case None => markerJson
}
def filterMarkers[A](encoder: Encoder.AsObject[A]): Encoder.AsObject[A] =
encoder.mapJsonObject { obj =>
obj.filter {
case (_, value) => value =!= markerJson
}
}
}

Scala: execute anonymous code block for None value in Option

Option class has a good method foreach, which calls passed code if value is specified. Is there any similar techinque for None value? I know about .orElse method, but, using it, I am required to return Option from code block:
x orElse {
// do something
None // <-- I want to avoid this line
}
If you want to do something in the None case I assume you are side-effecting. So what's wrong with:
if(o.isEmpty){
// do things
}
I don't think that it exists in standard Option library, but you can add it with implicit class
class OptionFunctions[T](val opt: Option[T]) extends AnyVal {
def ifEmpty[A](f: => A): Unit = {
if (opt.isEmpty) f
}
}
and use it like this:
val o = Some(1)
o.ifEmpty { println("empty") }
A pattern match perhaps?
option match {
case Some(foo) => println("Have " + foo)
case None => println("Have nothing.")
}

Extending Enumeration

I've implemented a method withNameOption that returns None if the enumeration member with specific name is not found but I have trouble extracting it to a trait to use it for all the enumerations in the app. At the moment code looks like this:
object FileType extends Enumeration with EnumUtils {
type FileType = Value
def withNameOption(name: String): Option[FileType] = try {
Some(withName(name))
} catch {
case _: NoSuchElementException => None
}
val scala, java, ruby = Value
}
Using this.type wherever possible doesn't typecheck.
I think this is the pattern you're looking for:
trait EnumUtils {
thisenum: Enumeration =>
def withNameOption(name: String): Option[thisenum.type#Value] = try {
Some(thisenum.withName(name))
} catch {
case _: NoSuchElementException => None
}
}
object FileType extends Enumeration with EnumUtils {
type FileType = Value
val scala, java, ruby = Value
}
object Test {
def main(args: Array[String]): Unit = {
println("Python: " + FileType.withNameOption("python"))
println("Scala: " + FileType.withNameOption("scala"))
}
}
What is the specific error you're seeing?
You might prefer to use the "pimp my library pattern" to add this method onto existing Enumerations, rather than using a trait.

Scala pattern matching on generic Map

Whats the best way to handle generics and erasure when doing pattern matching in Scala (a Map in my case). I am looking for a proper implementation without compiler warnings. I have a function that I want to return Map[Int, Seq[String]] from. Currently the code looks like:
def teams: Map[Int, Seq[String]] = {
val dateam = new scala.collection.mutable.HashMap[Int, Seq[String]]
// data.attributes is Map[String, Object] returned from JSON parsing (jackson-module-scala)
val teamz = data.attributes.get("team_players")
if (teamz.isDefined) {
val x = teamz.get
try {
x match {
case m: mutable.Map[_, _] => {
m.foreach( kv => {
kv._1 match {
case teamId: String => {
kv._2 match {
case team: Seq[_] => {
val tid: Int = teamId.toInt
dateam.put(tid, team.map(s => s.toString))
}
}
}
}
})
}
}
} catch {
case e: Exception => {
logger.error("Unable to convert the team_players (%s) attribute.".format(x), e)
}
}
dateam
} else {
logger.warn("Missing team_players attribute in: %s".format(data.attributes))
}
dateam.toMap
}
Use a Scala library to handle it. There are some based on Jackson (Play's ScalaJson, for instance -- see this article on using it stand-alone), as well as libraries not based on Jackson (of which my preferred is Argonaut, though you could also go with Spray-Json).
These libraries, and others, solve this problem. Doing it by hand is awkward and prone to errors, so don't do it.
It could be reasonable to use for comprehension (with some built in pattern matching). Also we could take into account that Map is a list of tuples, in our case of (String, Object) type. As well we will ignore for this example probable exceptions, so:
import scala.collection.mutable.HashMap
def convert(json: Map[String, Object]): HashMap[Int, Seq[String]] = {
val converted = for {
(id: String, description: Seq[Any]) <- json
} yield (id.toInt, description.map(_.toString))
HashMap[Int, Seq[String]](converted.toSeq: _*)
}
So, our for comprehension taking into account only tuples with (String, Seq[Any]) type, then combines converted String to Int and Seq[Any] to Seq[String]. And makes Map to be mutable.